Документация InstantCMS

для администраторов и разработчиков

Инструменты пользователя

Инструменты сайта


Control Panel Tables

InstantCMS 2 provides an automatic output of table entries (lists) in the component's control panel.

The easiest way to consider the work of automatic tables is to consider them with the help of an example.

Let the «Guestbook» (guestbook) component, which allows to post messages on the site, be an illustrative example. Each message has three fields: author's name (author), publication date (date_pub) and message text (content). We want to output all messages in one table in the component's control panel.

Suppose, we have already created a control panel's controller (backend.php) and the index action is defined in it:

class backendGuestbook extends cmsBackend { 
    public function actionIndex(){

The messages are stored in the guestbook_messages table in the database. The table has fields: id, author, date_pub, content.

The component's Model has the getMessages() method returning a list of messages and the getMessagesCount() method returning message count:

class modelGuestbook extends cmsModel {
    public function getMessages(){
        return $this->get('guestbook_messages');
    public function getMessagesCount(){
        return $this->getCount('guestbook_messages');

Now we want the index action of the component's control panel to get all messages from the database and output them in the form of a table.

Creating Table Description

The system should know what columns it will contain to generate a table. For this reason a description file is created. Such files are stored in the /system/controllers/{component}/backend/grids folder. Each file is called grid_{table_title}.php. Inside the file, the grid_{table_title}() function returning an array with three fields is defined :

optionsTable options
columnsTable column (field) description
actionsEach row's options (edit, delete, etc.)

In our example, the table can be called messages and be located in the /system/controllers/guestbook/backend/grids/grid_messages.php file. The following function is declared inside:

function grid_messages($controller){
    $options = array();
    $columns = array();
    $actions = array();
    return array(
        'options' => $options,
        'columns' => $columns,
        'actions' => $actions

The incoming $controller parameter contains a link to the controller's object (backendGuestbook).

Table options

The $options array that is returned above should contain a list of table options. Available options:

TitleDescriptionPossible values
is_sortableYou can sort the table by columnstrue or false
is_filterYou can filter the table by certain columnstrue or false
is_paginationPaginated table viewtrue or false
is_draggableUse your mouse to drag and drop table rowstrue or false
order_byA field by which table rows are sorted by defaultfield title
order_toDefault sorting orderasc or desc
show_idShow column with the id field in the tabletrue or false

In our example, we want to output a sortable paginated table with filters by fields. By default, messages are sorted by date, ascendingly. Let's fill the $options array:

    $options = array(
        'is_sortable' => true,   // sort by columns
        'is_filter' => true,     // filter by certain columns
        'is_pagination' => true, // paginated view
        'is_draggable' => false, // disable drag and drop
        'order_by' => 'date_pub',// sort by publication date
        'order_to' => 'desc',    // descending (new first)
        'show_id' => true        // show the id column

Table fields

In the table description, the $columns array will contain the description of each column (field). Each $columns element corresponds to one field, while the element key corresponds to the field title in the incoming data (taken from a model).

For example, let's add a column with the id field:

    $columns = array(
        'id' => array(
            'title' => 'id', // Column name 
            'width' => 30, // Column width, in pixels
            'filter' => 'exact' // Filter by column - exact match search

Each field may have several options:

titleColumn name in a table
widthColumn width, in pixels and percent (in this case, it is specified as a string, for example, «40%»)
hrefField URL. Allows to convert fields into URLs. For example, if you need a field value to refer to the relevant entry's customization form. See more below
href_handler :!: For InstantCMS 2.7.0 and newer. function($row){} anonymous function. Gets the entire entry (row) as an array. Should return true or false. If it returns true - the field will become a link (if the href option is secified). If it returns false, the field will not become a link even if the href function is specified.
flagIf true is specified, it allows to output the field value in the form of a check. If the field contains one or is not empty, a green check will be displayed, if 0 or empty – grey check
flag_onAllows to enter a precise value with which the field is considered to be filled. In this case, the green check will be displayed only if the field value coinsides with the specified one
flag_toggleAllows to enter a URL to send a message to and notify about clicks on a checkbox in the field. This can be used, for example, to quickly switch the field value at one click. A processor at the specified URL should return a JSON-object with two fields: error – Error (true or false), is_on – Flag's new state (true or false). You can use a Universal URL
filterEnables the column filter. It is the filter type that is passed as a value – exact (exact match) or like (partial match). If the filter type is specified, the column will contain a text field to enter the filter condition.
handlerAn anonymous function with two incoming parameters: function($field, $row){ }, where $field is the current field's value, $row – entire row. The function should return the processed $field value. It is used to format the values, which are output in the table (for example, to add a currency sign to a price in numeric fields)
editable Enables inline customization of the field. The option contains an array that may contain two cells: table (mandatory) and save_action (optional). The table cell will contain the title of the table, into which this field's changes will be entered; an action that will get data for saving is specified in the save_action cell. If the save_action cell is not specified, a system action is used, it is enough in most cases. Please note that the table table should contain an increment id field with a unique entry identifier.

As for our guestbook example, the array of columns will look as follows:

$columns = array(
    'id' => array(
        'title' => 'id',
        'width' => 30,
        'filter' => 'exact'
    'author' => array(
        'title' => LANG_AUTHOR,
        'filter' => 'like'
    'date_pub' => array(
        'title' => LANG_DATE,
        'filter' => 'like', 
        'handler' => function ($field, $row){
            return date('d.m.Y', strtotime($field));
    'content' => array(
        'title' => LANG_MESSAGE,
        'filter' => 'like', 
        'handler' => function ($field, $row){
            return mb_strlen($field) > 100 ? mb_substr($field, 0, 100) : $field;

We additionally process the date_pub and content fields with the help of the handler option. In the first case, we bring data to a proper format, in the second, we truncate messages that are more than 100 symbols long. We enable a strict filter for the id field, for the rest – filters by partial match.

URLs from table fields

When outputting fields in a table, you can turn any field into an active link. For this the href option is used in the field (column) description. The link's URL can be this option's value. You can substitute any current table entry's (row's) field values inside the URL. This is done with the help of the {field_title} expression.

For example, each guestbook message is available at http://site/guestbook/message/123, where 123 is a message ID in the database. We want each message text of our message table in the control panel be a link to the message page. Then we can add the href option for the content column:

    'content' => array(
        'title' => LANG_MESSAGE,
        'filter' => 'like', 
        'handler' => function ($field, $row){
            return mb_strlen($field) > 100 ? mb_substr($field, 0, 100) : $field;
        'href' => href_to('guestbook', 'message', '{id}')

To generate a URL, we use the href_to() function returning the URL of the required action with parameters. We specify {id} as a parameter, in other words, the value of a corresponding field for this row.

Table actions

The icons of actions applicable to each row (such as editing, deleting, etc.) are usually located in the last table column:

The $actions array in the table description contains a list of available actions for rows. Each action is represented by a nested array that may have the following fields:

titleAn action's caption appears when pointing a mouse cursor over an icon
classa class, in which an action icon is described. For more information see below
hrefA link (URL) to an action performing this action
confirmA confirmation text that will appear at an attempt to perform an action. For example, «Are you sure?». You can substitute the fields with the help of the {field_title} expression in the text.
handlerfunction($row){} anonymous function. Gets the entire entry (row) as an array. Should return true or false. If it returns false, the action will not be displayed for this row. It is used, for example, to forbid the deletion of certain rows.

In our guestbook example, each message can have 3 actions – «view on site», «edit», «delete»:

$actions = array(
        'title' => LANG_VIEW,
        'class' => 'view',
        'href' => href_to('guestbook', 'message', '{id}')
        'title' => LANG_EDIT,
        'class' => 'edit',
        'href' => href_to($controller->root_url, 'edit', '{id}')
        'title' => LANG_DELETE,
        'class' => 'delete',
        'href' => href_to($controller->root_url, 'delete', '{id}'),

The first action refers to the /guestbook/message frontend action, while the next too – to control panel actions. In this case, the $controller→root_url property is inserted at the beginning of a URL replacing the controller title that contains the root path for the component's backend-controller in the control panel.

A confirmation that is specified by a constant in the component's Language File is used for the «Delete» action:

define('LANG_GUESTBOOK_MESSAGE_DELETE_CONFIRM', 'Delete message №{id}?');

In the message, the {id} expression will be replaced with the ID of a deleted row.

Action icons

CSS-class is used to output an action icon. Standard classes:

Class → Icon Class → Icon
view accept
edit play
config rss
labels user
fields unbind
filter delete
permissions relations

You can define your own my_class class in the /templates/default/controllers/{component}/backend/styles.css file:

.datagrid .actions a.my_class { background-image: url("../../images/icons/my_icon.png"); }

In this example, the /templates/default/images/icons/my_icon.png icon will be used.

Table output

Once the file with table structure description is ready, you need to output the table and fill it with data. This process has several stages:

  1. Table body is output in the template of a proper action;
  2. An AJAX-request is sent to get data;
  3. Received data is added to the table;
  4. When editing a page, sorting or table filters, go back to s.2.

Table output in a template

To output a table in the template, upload its description first. This is done in the action code with the help of custom loadDataGrid($grid_name) method:

$grid = $this->loadDataGrid('my_grid');

To save the sorting in your table (if there is sorting), use the following code to load the table description when outputting it:

$grid = $this->loadDataGrid('my_grid', false, 'my_component.my_key');

where my_component is your component's title (for example, guestbook), my_key - some key explicitly identifying this table.

Then the received $grid array is passed to a template to be output with the help of the renderGrid($data_url, $grid) method:

<?php $this->renderGrid($this->href_to('action'), $grid); ?>

The first parameter of this method contains an action URL that will return data to output it in the table (rows). This data is returned in the JSON format by an AJAX-request. The second parameter passes the table description object received earlier in the action.

As a result, a table body is formed on the page, i.e. an empty table that has only column captions. In this form, the table is sent to a user. The data is loaded once the page is displayed to a user, asynchronously.

Let's go back to our guestbook example. Let's add an ability to load and output a table in a controller, control panel and template.

/system/controllers/guestbook/backend.php controller :

class backendGuestbook extends cmsBackend { 
    public function actionIndex(){
        // we upload the table description    
        $grid = $this->loadDataGrid('messages');
        // we link the tepmplate and pass description into it
        return cmsTemplate::getInstance()->render('backend/index', array(
            'grid' => $grid

/templates/default/controllers/guestbook/backend/index.tpl.php template:

<h3>Message list</h3>
<?php $this->renderGrid($this->href_to('messages_ajax'), $grid); ?>

Uploading data to a table

A separate action, which outputs nothing to a browser and returns a JSON-array with table rows, is usually used to load data.

Inside the action, the following issues takes place:

  1. Uploading table description;
  2. Linking component model;
  3. Receiving data about filters from a request;
  4. If there is a before saved filter, we get it or save the filter received above;
  5. Applying filters to a model;
  6. Receiving selected data from a model;
  7. Forming and outputting the result in the form of JSON.

In the example above, in the template, we have specified the messages_ajax action as data source when generating a table.

We add this action to a controller:

public function actionMessagesAjax(){
    // we check if it is an AJAX-request
    if (!$this->request->isAjax()) { cmsCore::error404(); }
    // we upload the table description
    $grid = $this->loadDataGrid('messages');
    // we get a custom model
    $model = cmsCore::getModel($this->name);
    // we specify the default number of rows on one table page
    // we prepare an array that will contain
    // filtering conditions (including page number and sorting)
    $filter = array();
    // getting filter description from a request 
    $filter_str = $this->request->get('filter', '');
    // if there is nothing in $filter_str, we load an earlier saved filter, if there is one 
    // or if there is data in $filter_str, we refresh the filter
    $filter_str = cmsUser::getUPSActual('my_component.my_key', $filter_str);
    if ($filter_str){ // if there are filters,
        // we parse the received row with conditions and fill the $filter array
        parse_str($filter_str, $filter);
        // we apply table filters to a model
        $model->applyGridFilter($grid, $filter);
    // we get an overall number of rows, taking into account all filters
    $total = $model->getMessagesCount();
    // we get the number of rows on a page or the default value
    $perpage = isset($filter['perpage']) ? $filter['perpage'] : admin::perpage;
    // we calculate the number of pages
    $pages = ceil($total / $perpage);
    // from a model, we get entries (strings) meeting filtering conditions
    $messages = $model->getMessages();
    // we link the template object
    $template = cmsTemplate::getInstance();
    // we ask the template to render the JSON array with table rows
    $template->renderGridRowsJSON($grid, $messages, $total, $pages);
    $this->halt(); // finish

Please note that analyzing the filters and applying them to a model is reasonable only if your table has pagination, sorting or filters (i.e. if any of the options is enabled – is_sortable, is_filter or is_pagination).

We have considered the simplest case when all information is stored in one DB table.

Of course, in real practice, you may need to output data from several linked tables. This is what you need to do following the method described in the «Model» section. Moreover, you can create a table that outputs data not from the Database or another site's DB and so on. In the following string:

$template->renderGridRowsJSON($grid, $data, $total, $pages);

the table structure in the $grid parameter must correspond to the $data array structure. Everything will be correct then.

Back to Controllers

en/dev/controllers/backend/grids.txt · Последнее изменение: 11.05.2017 16:40 — murlysja