Magento 2: Створення гріду в adminhtml

Коротка пам'ятка по створенню гридов в адмінці Magento 2. В якості прикладу я взяв простий грід з трьох колонок, дані для якого (коди країн з ISO 3166) поставляються з прописаного в коді масиву. Для того, щоб сфокусуватися на основних аспектах побудови гріду я відкинув з дескриптора UI-компоненти максимум можливого (додаткові кнопки, фільтри, сортування, bookmarks, ...) і частина налаштувань переніс в конструктор провайдера даних для гріду. Якщо можна зробити ще коротше без втрати читабельності — з максимальним задоволенням зроблю відповідні правки. Код прикладу на github'е — flancer32/sample_mage2_admin_grid.

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
(видимий ідентифікатор, частина ДО а):
<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 $_resultPageFactory;

public function __construct(
\Magento\Backend\App\Action\Context $context,
\Magento\Framework\View\Result\PageFactory $resultPageFactory
) {
parent::__construct($context);
$this->_resultPageFactory = $resultPageFactory;
}

protected function _isAllowed()
{
$result = $this->_authorization->isAllowed(self::ACL_RESOURCE);
return $result;
}

public function execute()
{
/** @var \Magento\Backend\Model\View\Result\Page $resultPage */
$resultPage = $this->_resultPageFactory->create();
$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->getRouteUrl('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'а!
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.