
Введение
Привет! Меня зовут Павел и я Magento 2 бэкенд-разработчик. В прошлых частях саги о Magento 2 UI Components мы получили общие сведения о UI-компонентах, а также рассмотрели наиболее важные аспекты их конфигурации. Сегодня подробно коснемся некоторых вопросов модификации UI компонентов под свои нужды: изменение внешнего вида, поведения клиентской части, поведения серверной части и пр. Погнали!
Изменение внешнего вида
Начнем с наиболее простой части — изменение внешнего вида. У всех компонентов, имеющих какое либо визуальное представление, внешний вид задается шаблоном. Для примера возьмем шаблон компонента Input:
<input class="admin__control-text" type="text" data-bind=" event: {change: userChanges}, value: value, hasFocus: focused, valueUpdate: valueUpdate, attr: { name: inputName, placeholder: placeholder, 'aria-describedby': noticeId, id: uid, disabled: disabled, maxlength: 255 }"/>
Попробуем изменить его, для чего в нашем модуле создадим файл input.html в /view/adminhtml/web/templates/form/element/ нашего модуля и поместим туда следующий текст:
<span>White Rabbit</span><!-- добавим элемент для наглядности --> <input class="admin__control-text" type="text" data-bind=" event: {change: userChanges}, value: value, hasFocus: focused, valueUpdate: valueUpdate, attr: { name: inputName, placeholder: placeholder, 'aria-describedby': noticeId, id: uid, disabled: disabled, maxlength: 255 }"/>
После чего в xml конфигурации, где объявлен наш компонент, укажем новый шаблон для компонента примерно таким образом:
<field name="white_rabbit" sortOrder="10" formElement="input"> <argument name="data" xsi:type="array"> <item name="config" xsi:type="array"> ... <item name="elementTmpl" xsi:type="string">RSHB_WhiteRabbit/form/element/input</item> ... </item> </argument> </field>
Очистим кэш и посмотрим, как изменился внешний вид компонента:

Вместе с кастомизацией шаблона мы можем расширить функционал UI-компонента, например, использовать в шаблоне knockout конструкции, которые будут обращаться к кастомным методам JS-компонента.
Кастомизация JS-компонента
Перейдем к более интересному моменту, а именно — к управлению поведением компонента в браузере пользователя. Как мы помним из предыдущей статьи, одной из частей UI-компонента является JS-виджет, который обеспечивает интерактивность компонента и отвечает за его поведение. Многие простейшие компоненты, такие как рассмотренный ранее input, не имеют своей реализации JS-компонента, вместо этого используя общую для всех реализацию abstract (которую можно найти в <magento_root>/vendor/magento/module-ui/view/base/web/js/form/element/abstract.js).
Поэтому, посмотрим на один из самых простых специализированных JS-компонентов — компонент Textarea:
define([ './abstract' ], function (Abstract) { 'use strict'; return Abstract.extend({ defaults: { cols: 15, rows: 2, elementTmpl: 'ui/form/element/textarea' } }); });
Как мы видим, данный компонент расширяет реализацию abstract и вносит минимум изменений, а именно, задает размеры поля по умолчанию и его шаблон (тот самый, который мы обсуждали ранее).
У нас есть два пути модификации JS-компонента.
В первом случае, если мы хотим кардинально изменить поведение компонента, то можно написать новый JS-компонент, и указать его в xml конфигурации UI-компонента вместо использующегося по умолчанию. Для этого в нашем модуле создадим файл textarea.js по адресу view/adminhtml/web/js/form/element/, поместим туда модифицированный JS-компонент, а затем укажем его в xml конфигурации следующим образом:
<field name="white_rabbit" sortOrder="10" formElement="textarea"> <argument name="data" xsi:type="array"> <item name="config" xsi:type="array"> ... <item name="component" xsi:type="string">RSHB_WhiteRabbit/js/form/element/textarea</item> ... </item> </argument> </field>
Стоит заметить, что если нет нужды переписывать весь компонент, то достаточно его расширить, если вносимые изменения незначительны:
define([ 'Magento_Ui/js/form/element/textarea' ], function (MagentoTextarea) { 'use strict'; return MagentoTextarea.extend({ sayHello: function () { alert('Hello!'); return this; }, }); });
Так мы добавили нашему компоненту функцию sayHello которую можно использовать по своему смотрению.
Альтернативой полной замене JS-компонента может служить миксин к базовому JS-компоненту. В отличие от описанного ранее, данный метод поменяет поведение всех экземпляров компонента в системе, это следует держать в голове при выборе способа модификации JS-компонента.
Чтобы изменить поведение компонента при помощи миксина, необходимо создать миксин и указать его в requirejs. Для примера, применим миксин к базовому компоненту form, для чего поместим файл requirejs-config.js в /view/base/ нашего модуля:
var config = { 'config': { 'mixins': { 'Magento_Ui/js/form/form': { 'RSHB_WhiteRabbit/form-hook': true } } } };
И далее разместим в /view/base/web/form-hook.js нашего модуля код мисксина:
define([], function () { 'use strict'; return function (Form) { return Form.extend({ initialize: function () { this._super(); console.log('The mixin from White Rabbit!'); } }); } });
Таким образом, мы дополнили функцию инициализации компонента Form нашим кодом, и теперь каждый раз при выводе компонента Form в консоли будет выводиться строка “The mixin from White Rabbit!”.
PHP-классы
Теперь рассмотрим модификацию серверной части UI-компонента. Для этой цели служат кастомные классы компонентов и PHP-модификаторы (о последних поговорим позже).
Представим ситуацию, когда в базе у нас лежит значение int, которое определяет, включен некий параметр, или нет (значения 1 или 0, аналогично булевым true-false). При использовании стандартного класса column в гриде, мы увидим в колонке значения 1 или 0, в зависимости от значения в базе. Если мы хотим выводить эти значения как “Включено” или “Выключено”, нам необходимо подменить класс компонента, например:
<?php ... class OnOff extends \Magento\Ui\Component\Listing\Columns\Column { /** * OnOff constructor * * @param ContextInterface $context * @param UiComponentFactory $uiComponentFactory * @param array $components * @param array $data */ public function __construct( ContextInterface $context, UiComponentFactory $uiComponentFactory, array $components = [], array $data = [] ) { parent::__construct($context, $uiComponentFactory, $components, $data); } /** * @param array $dataSource * @return array */ public function prepareDataSource(array $dataSource) { if (isset($dataSource['data']['items'])) { foreach ($dataSource['data']['items'] as $id => $item) { $whiteRabbit = $item['white_rabbit'];//Находим поле с нужным именем whi $item['white_rabbit'] = (bool)$whiteRabbit ? 'On' : 'Off'; $dataSource['data']['items'][$id] = $item; } } return $dataSource; } }
Как мы видим, кастомный класс компонента меняет значения 1 и 0 на “Включено” и “Выключено”.
Стоит помнить, что при изменении значения в колонке нужно также изменять значения в фильтрах (если для колонки предусмотрен фильтр). Для этого следует указать Source класс со значениями, которые соответствуют значениям “Включено” и “Выключено” в нашем примере. Код Source класса:
<?php ... class OnOff implements \Magento\Framework\Option\ArrayInterface { /** * @return array */ public function toOptionArray(): array { return [['value' => 1, 'label' => __('On')], ['value' => 0, 'label' => __('Off')]]; } /** * @return array */ public function toArray(): array { return [0 => __('Off'), 1 => __('On')]; } }
Кстати, в М2 есть ряд предопределенных Source классов для наиболее распространенных задач, например, значения Yes/No, перечень категорий товаров и пр.
PHP-модификаторы
Еще одним любопытным способом изменить или дополнить поведение серверной части UI-компонента (а именно, его дата-провайдера) — PHP модификаторы. Они применяются в случаях, когда статическое объявление PHP класса в XML конфигурации по каким-то причинам не подходит, или может вызвать избыточное дублирование кода.
PHP модификатор должен реализовывать Magento\Ui\DataProvider\Modifier\ModifierInterface и должен содержать два метода: modifyData() и modifyMeta(). Посмотрим пример такого модификатора:
<?php ... class WhiteRabbitModifier implements Magento\Ui\DataProvider\Modifier\ModifierInterface { /** * {@inheritdoc} */ public function modifyMeta(array $meta) { $meta['test_fieldset_name'] = [ 'arguments' => [ 'data' => [ 'config' => [ 'label' => __('Label For Fieldset'), 'sortOrder' => 50, 'collapsible' => true ] ] ], 'children' => [ 'test_field_name' => [ 'arguments' => [ 'data' => [ 'config' => [ 'formElement' => 'select', 'componentType' => 'field', 'options' => [ ['value' => 'test_value_1', 'label' => 'Test Value 1'], ['value' => 'test_value_2', 'label' => 'Test Value 2'], ['value' => 'test_value_3', 'label' => 'Test Value 3'], ], 'visible' => 1, 'required' => 1, 'label' => __('Label For Element') ] ] ] ] ] ]; return $meta; } /** * {@inheritdoc} */ public function modifyData(array $data) { return $data; } }
Как мы видим, при помощи модификатора можно изменить данные и мета-данные UI-компонента.
Для того, чтобы модификатор заработал, его нужно добавить в пул модификаторов дата-провайдера через di.xml таким способом:
<virtualType name="RSHB\WhiteRabbit\DataProvider\Modifier\WhiteRabbitPool" type="Magento\Ui\DataProvider\Modifier\Pool"> <arguments> <argument name="modifiers" xsi:type="array"> <item name="modifier_name" xsi:type="array"> <item name="class" xsi:type="string">RSHB\WhiteRabbit\Modifier\WhiteRabbitModifier</item> <item name="sortOrder" xsi:type="number">10</item> </item> </argument> </arguments> </virtualType> <type name="RSHB\WhiteRabbit\Ui\DataProvider\WhiteRabbitDataProvider"> <arguments> <argument name="pool" xsi:type="object">RSHB\WhiteRabbit\DataProvider\Modifier\WhiteRabbitPool</argument> </arguments> </type>
Заключение
Мы рассмотрели основные аспекты модификации UI-компонентов под свои нужды. На этом цикл статей об UI-компонентах я считаю закрытым, возникающие вопросы по нюансам работы можно задавать в комментариям к соответствующим статьям.
Пишите код с удовольствием! До встречи.
