Step 1. Implement actions in the controller.

When implementing a new page with a list on it, you need to specify two actions in the controller:

public function listAction()
{
    $list = $this->_getNumbersList();

    // List object for pm_View_Helper_RenderList
    $this->view->list = $list;
}

public function listDataAction()
{
    $list = $this->_getNumbersList();

    // Json data from pm_View_List_Simple
    $this->_helper->json($list->fetchData());
}

The first action defines the action itself and will have a view defined in list.phtml. It loads the list and passes it to the view. The second action defines the way the list can retrieve the data in JSON format. This action is used when the user changes the sorting method in the list, or proceeds to the next page (when there are, for example, 30 rows in the list and only 25 are displayed per page). In this case, instead of reloading the whole page, only the list is reloaded using AJAX request to the data action of the list.

Step 2. Implement the List object.

Now, it is time to implement the list itself. In order to to be correctly rendered in the view, it must be an instance of pm_View_List_Simple. We recommend implementing it as private method in the controller:

private function _getNumbersList()
{
    $data = [];
    $iconPath = pm_Context::getBaseUrl() . 'images/icon_16.gif';
    for ($index = 1; $index < 150; $index++)
    {
        $data[] = [
            'column-1' => '<a href="#">link #' . $index . '</a>',
            'column-2' => '<img src="' . $iconPath . '" /> image #' . $index,
        ];
    }

    $list = new pm_View_List_Simple($this->view, $this->_request);
    $list->setData($data);
    $list->setColumns([
        'column-1' => [
            'title' => 'Link',
            'noEscape' => true,
            'searchable' => true,
        ],
        'column-2' => [
            'title' => 'Description',
            'noEscape' => true,
            'sortable' => false,
        ],
    ]);

    // Take into account listDataAction corresponds to the URL /list-data/
    $list->setDataUrl(['action' => 'list-data']);
    return $list;
}

Pay attention to the setDataUrl, where we implicitly specify which action is used to retrieve data. Also, we can implement the list as a separate class which extends the pm_View_List_Simple. In this case, the class is placed in plib/library, and the controller will just create an instance of it. This makes it possible, for example, to reuse the list in a different spot, or to create a hierarchy of lists to reuse the implemented functionality. As an example of such approach, you can refer to the implementation of the list and how it’s is called in controller (listAction and listDataAction methods).

Step 3. Define the view

When you implement the list using pm_View_List_Simple, the view (in a .phtml file) is very simple and uses the pm_View_Helper_RenderList helper to render it:

<?php echo $this->renderList($this->list); ?>

Now, you can visit the list action of your extension and check the result:

image 79427

Moreover, you can see what the list would look like on a Plesk server using a different color scheme or branding (for example, when the Skins and Color Schemes extension is installed), or how the list would look in adaptive design on a mobile device.

Setting Default Column for Sorting

Starting with Plesk 12.5, it is possible to specify the default column for sorting via the options on creation of a pm_View_List_Simple class object.

$options = [
    'defaultSortField' => 'column-1',
    'defaultSortDirection' => pm_View_List_Simple::SORT_DIR_DOWN,
];

$list = new pm_View_List_Simple($this->view, $this->_request, $options);
$list->setData($data);
$list->setColumns([
    pm_View_List_Simple::COLUMN_SELECTION,
    'column-1' => [
        'title' => 'Link',
        'noEscape' => true,
       'searchable' => true,
    ],
    'column-2' => [
        'title' => 'Description',
        'noEscape' => true,
       'sortable' => false,
    ],
]);

Adding Toolbar to the List

Most lists in Plesk include a toolbar with buttons, and manipulating objects in the list using those buttons is a common user experience. Starting with Plesk 12.5, it is possible to implement group operations using SDK. You can define the buttons appearing on your list using the setTools method. The buttons can invoke several operations, such as navigating to a different page. The Add button is, probably, the one used most frequently. You can use helpers from pm_Context to compose the URL:

$list->setTools([
    [
        'title' => 'Button 1',
        'description' => 'Link to list of extensions',
        'link' => pm_Context::getModulesListUrl() ,
    ], [
        'title' => 'Button 2',
        'description' => 'Link to index page of the extension',
        'link' => pm_Context::getBaseUrl() ,
    ], [
        'title' => 'Button 3',
        'description' => 'Link to controller custom and action test of the extension',
        'controller' => 'custom',
        'action' => 'test',
    ],
]);

The buttons defined above will appear on the page like this:

image 79426

Another frequently encountered scenario is to implement a group operation with the selected objects. For this purpose, you need to add a column with checkboxes to the list:

$list->setColumns([
    pm_View_List_Simple::COLUMN_SELECTION,

    // all other columns
]);

image 79428

And then add a button with the specified property execGroupOperation:

$list->setTools([
    [
        'title' => 'Hide',
        'description' => 'Make selected rows invisible.',
        'execGroupOperation' => [
            'submitHandler' => 'function(url, ids) {
                $A(ids).each(function(id) {
                    $("' . $list->getId() . '")
                        .select("[name=\'listCheckbox[]\'][value=\'" + id.value + "\']")
                        .first()
                        .up("tr")
                        .hide();
                });
            }'
        ],
    ], [
        'title' => 'Remove',
        'description' => 'Remove selected rows.',
        'execGroupOperation' => $this->_helper->url('remove') ,
    ],
]);

For the case where you specify the URL of a controller and the action that is to process the group operation, implement the action in the controller:

public function removeAction()
{
    $messages = [];
    foreach((array)$this->_getParam('ids') as $id) {

        // Here we should remove the object with id = $id

        $messages[] = ['status' => 'info', 'content' => "Row #$id was successfully removed."];
    }
    $this->_helper->json(['status' => 'success', 'statusMessages' => $messages]);
}

Pay attention that processing of group operation is also made by AJAX request the same as changing ordering described above. So the action should respond with JSON.

More code samples are available as part of this example extension: https://github.com/plesk/ext-example/blob/master/plib/controllers/IndexController.php