Magento 2 UI Components. Часть 3: модификация

от автора

Введение

Привет! Меня зовут Павел и я 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>

Очистим кэш и посмотрим, как изменился внешний вид компонента:

Измененный шаблон компонента Input
Измененный шаблон компонента Input

Вместе с кастомизацией шаблона мы можем расширить функционал 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-компонентах я считаю закрытым, возникающие вопросы по нюансам работы можно задавать в комментариям к соответствующим статьям.

Пишите код с удовольствием! До встречи.


ссылка на оригинал статьи https://habr.com/ru/articles/575432/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *