Краткая памятка по созданию гридов в админке Magento 2. В качестве примера я взял простой грид из трех колонок, данные для которого (коды стран по ISO 3166) поставляются из прописанного в коде массива. Для того, чтобы сфокусироваться на основных аспектах построения грида я отбросил из дескриптора UI-компонента максимум возможного (дополнительные кнопки, фильтры, сортировка, bookmarks, ...) и часть настроек перенес в конструктор провайдера данных для грида. Если можно сделать еще короче без потери читабельности — с максимальным удовлетворением внесу соответствующие правки (UPD: спасибо коллеге Oxidant за контроллер). Код примера на github'е.

ACL
Создаем запись в ACL (./etc/acl.xml) для контроля доступа к гриду:
<?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Acl/etc/acl.xsd"> <acl> <resources> <resource id="Magento_Backend::admin"> <resource id="Flancer32_Sample::sample" title="Samples" sortOrder="10"> <resource id="Flancer32_Sample::sample_grid" title="Grid" sortOrder="100"/> </resource> </resource> </resources> </acl> </config>
Menu
Добавляем в меню админки (./etc/adminhtml/menu.xml) дополнительные пункты:
<?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Backend:etc/menu.xsd"> <menu> <add id="Flancer32_Sample::sample" title="Sample" translate="title" module="Flancer32_Sample" sortOrder="15" resource="Flancer32_Sample::sample"/> <add id="Flancer32_Sample::sample_grid" title="Grid" translate="title" module="Flancer32_Sample" sortOrder="100" parent="Flancer32_Sample::sample" action="sample/grid" resource="Flancer32_Sample::sample_grid"/> </menu> </config>
Адрес перенаправления определяется в action="...", доступ к пунктам меню — в resource="...".
Routes
В файле ./etc/adminhtml/routes.xml регистрируем маршурт fl32_sample_route (внутренний идентификатор) с именем sample (видимый идентификатор, часть URL'а):
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd"> <router id="admin"> <route id="fl32_sample_route" frontName="sample"> <module name="Flancer32_Sample"/> </route> </router> </config>
Controller
Обработчики запросов по адресу .../index.php/admin/sample/grid/* размещаем в каталоге ./src/Controller/Adminhtml/Grid/. Обработчик по-умолчанию: Index.php:
namespace Flancer32\Sample\Controller\Adminhtml\Grid; class Index extends \Magento\Backend\App\Action { const ACL_RESOURCE = 'Flancer32_Sample::sample_grid'; const MENU_ITEM = 'Flancer32_Sample::sample_grid'; const TITLE = 'Sample Grid'; protected function _isAllowed() { $result = parent::_isAllowed(); $result = $result && $this->_authorization->isAllowed(self::ACL_RESOURCE); return $result; } public function execute() { /** @var \Magento\Backend\Model\View\Result\Page $resultPage */ $resultPage = $this->resultFactory->create(\Magento\Framework\Controller\ResultFactory::TYPE_PAGE); $resultPage->setActiveMenu(self::MENU_ITEM); $resultPage->getConfig()->getTitle()->prepend(__(self::TITLE)); return $resultPage; } }
Все, что делает обработчик — проверяет права пользователя на доступ к гриду и формирует страницу в соответствии с заданным для данного маршрута laout'ом.
Layout
Описание layout'а находится в каталоге ./src/view/adminhtml/layout/ в файле fl32_sample_route_grid_index, название которого состоит из трех частей:
- fl32_sample_route: внтуренний идентификатор маршрута (см. route.id в ./etc/adminhtml/routes.xml);
- grid: вторая часть адреса перенаправления (см. action в ./etc/adminhtml/menu.xml);
- index: имя обработчика по-умолчанию для запросов по адресу .../index.php/admin/sample/grid/ (см. ./src/Controller/Adminhtml/Grid/Index.php);
<?xml version="1.0"?> <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd"> <body> <referenceContainer name="content"> <uiComponent name="sample_grid"/> </referenceContainer> </body> </page>
В описании задано, что в качестве контента на странице нужно вывести UI-компонент с именем sample_grid.
UI Component
Дескриптор компонента находится в файле ./src/view/adminhtml/ui_component/sample_grid.xml
<?xml version="1.0" encoding="UTF-8"?> <listing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd"> <argument name="data" xsi:type="array"> <item name="js_config" xsi:type="array"> <item name="provider" xsi:type="string">sample_grid.sample_grid_data_source</item> <item name="deps" xsi:type="string">sample_grid.sample_grid_data_source</item> </item> <item name="spinner" xsi:type="string">sample_grid_columns</item> </argument> <dataSource name="sample_grid_data_source"> <argument name="dataProvider" xsi:type="configurableObject"> <argument name="class" xsi:type="string">Flancer32\Sample\Ui\Component\DataProvider\Grid</argument> <argument name="name" xsi:type="string">sample_grid_data_source</argument> </argument> </dataSource> <columns name="sample_grid_columns"> <column name="code2"> <argument name="data" xsi:type="array"> <item name="config" xsi:type="array"> <item name="sorting" xsi:type="string">asc</item> <item name="label" xsi:type="string" translate="true">Alpha-2</item> </item> </argument> </column> <column name="code3"> <argument name="data" xsi:type="array"> <item name="config" xsi:type="array"> <item name="label" xsi:type="string" translate="true">Alpha-3</item> </item> </argument> </column> <column name="code_num"> <argument name="data" xsi:type="array"> <item name="config" xsi:type="array"> <item name="label" xsi:type="string" translate="true">Numeric</item> </item> </argument> </column> </columns> </listing>
Я постарался сделать код компонента как можно меньше (сравните с аналогичным для CMS Pages).
На что следует обратить внимание:
- имя компонента `sample_grid` совпадает с именем файла и используется в описании `js_config` (provider & deps);
- в настройках spinner'а указывается имя `columns`-компонента, после заполнения данными которого spinner скрывается;
- настройки data source'а спрятаны в конструкторе класса `Flancer32\Sample\Ui\Component\DataProvider\Grid`;
- имена столбцов грида совпадают с именами полей в данных;
- без указания настроек сортировки (`sorting`) хотя бы для одного столбца грид не загружается;
DataProvider
За поставку данных отвечает класс \Flancer32\Sample\Ui\Component\DataProvider\Grid. Конструктор принимает из дескриптора компонента только один параметр (name), все остальные либо инжектятся Object Manager'ом при создании провайдера данных, либо создаются в нем же. Данные не зависят от фильтров/сортировки и всегда возвращаются одни и те же (захардкожены в самом провайдере).
namespace Flancer32\Sample\Ui\Component\DataProvider; class Grid extends \Magento\Framework\View\Element\UiComponent\DataProvider\DataProvider { public function __construct( $name, \Magento\Framework\Api\Search\ReportingInterface $reporting, \Magento\Framework\Api\Search\SearchCriteriaBuilder $searchCriteriaBuilder, \Magento\Framework\App\RequestInterface $request, \Magento\Framework\Api\FilterBuilder $filterBuilder, \Magento\Framework\UrlInterface $url ) { $primaryFieldName = 'id'; $requestFieldName = 'id'; $meta = []; $updateUrl = $url->getUrl('mui/index/render'); $data = [ 'config' => [ 'component' => 'Magento_Ui/js/grid/provider', 'update_url' => $updateUrl ] ]; parent::__construct($name, $primaryFieldName, $requestFieldName, $reporting, $searchCriteriaBuilder, $request, $filterBuilder, $meta, $data); } public function getData() { $result = [ 'items' => [ ['code2' => 'AU', 'code3' => 'AUS', 'code_num' => '036'], ['code2' => 'AT', 'code3' => 'AUT', 'code_num' => '040'], ['code2' => 'AZ', 'code3' => 'AZE', 'code_num' => '031'] ], 'totalRecords' => 3 ]; return $result; } }
Резюме
Создание гридов в Magento 2 — это увлекательное занятие, которому можно посвятить не только свободные часы, но дни, а может быть даже и недели. Конечно, со временем оно станет менее увлекательным и более обыденным, но пока все еще остается возможность добавить в админку свой собственный грид не в пару кликов, а путем вдумчивого и кропотливого изменения если и не десятка файлов, то около того (если бы я трусливо не захаркодил данные в провайдере — точно достиг бы этого уровня, а может быть даже и превысил). Возможно кто-то окажется более смелым и захочет использовать встроенный \Magento\Framework\View\Element\UiComponent\DataProvider\DataProvider и зарегистрировать для него в ./src/etc/di.xml соответствующую коллекцию:
<type name="Magento\Framework\View\Element\UiComponent\DataProvider\CollectionFactory"> <arguments> <argument name="collections" xsi:type="array"> <item name="sample_grid_data_source" xsi:type="string">Vendor\Module\Model\ResourceModel\Grid\Collection</item> </argument> </arguments> </type>
Пожелаю ему в этом удачи. Я, к сожалению, на данный момент свой лимит увлекательности исчерпал.
Всем счастливого Magento 2 coding'а!
