Magento 2: рендерер для ячейки грида

в 7:41, , рубрики: adminhtml, Magento, magento 2, UI, рендеринг

Выход версии 2.3.0 приблизил использование PWA на фронте Magento-приложений на расстояние вытянутой руки. И если для фронта видны какие-то подвижки в применяемых технологиях, то с админкой всё гораздо стабильнее — старый добрый лабиринт из различных типов файлов, которые нужно поредактировать, чтобы на UI проявилось что-то полезное, усовершенствовать не планируется. В этой статье я описываю создание собственного рендерера для колонки грида в админке — вещи довольно несложной и, в то же самое время, довольно полезной при правильном применении. Например, рендерер для формирования в гриде заказов ссылки на карточку клиента, оформившего заказ:

image

Базовые компоненты рендерера

"Родной" рендерер для ссылок в Magento состоит из двух файлов:

В процессе обработки шаблона используются функции, предоставляемые кодом (объект $col). Входными данными для обработки являются также текущая строка грида (объект $row):

<div class="data-grid-cell-content"
     if="!$col.isLink($row())"
     text="$col.getLabel($row())"/>
<a   class="action-menu-item"
     if="$col.isLink($row())"
     text="$col.getLabel($row())"
     attr="href: $col.getLink($row())"/>

Данные для грида загружаются через провайдер данных. Типовой запрос примерно такой: "http://.../admin/mui/index/render/?namespace=sales_order_grid...". Структуру данных можно увидеть через панель инструментов разработчика в браузере. Для грида заказов она примерно такая:

{
  "items": [
    {
      "id_field_name": "entity_id",
      "entity_id": "1",
      "status": "pending",
      "store_id": "Main Website<br/>&nbsp;&nbsp;&nbsp;Main Website Store<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Default Store View<br/>",
      "store_name": "Main WebsitenMain Website Storen",
      "customer_id": "1",
      "base_grand_total": "RUB34.68",
      "base_total_paid": null,
      "grand_total": "RUB34.68",
      "total_paid": null,
      "increment_id": "000000001",
      "base_currency_code": "RUB",
      "order_currency_code": "RUB",
      "shipping_name": "Alex Gusev",
      "billing_name": "Alex Gusev",
      "created_at": "2018-12-22 19:35:19",
      "updated_at": "2018-12-22 19:35:20",
      "billing_address": "Street,Riga,Ru012bga,1010",
      "shipping_address": "Street,Riga,Ru012bga,1010",
      "shipping_information": "Flat Rate - Fixed",
      "customer_email": "alex@flancer64.com",
      "customer_group": "1",
      "subtotal": "RUB24.68",
      "shipping_and_handling": "RUB10.00",
      "customer_name": "Alex Gusev",
      "payment_method": "checkmo",
      "total_refunded": "RUB0.00",
      "signifyd_guarantee_status": null,
      "orig_data": null,
      "actions": {
        "view": {
          "href": "http://sample.local.flancer64.com/admin/sales/order/view/order_id/1/",
          "label": "View"
        }
      }
    }
  ],
  "totalRecords": 1
}

Собственный рендерер

Таким образом, для создания собственного рендерера нам нужно задать UI-компонент, состоящий из двух файлов:

  • JS-код компонента;
  • Knockout-шаблон компонента;

Моей текущей задачей является создание рендерера, который бы выводил в ячейку грида заказов ссылку на клиента, оформившего заказ. Для формирования ссылки на клиента мне нужно использовать идентификатор соответствующего клиента — customer_id. Можно написать свой собственный шаблон для рендеринга, но в данном случае меня вполне устраивает имеющийся шаблон (./module-ui/view/base/web/templates/grid/cells/link.html). Достаточно переписать JS-код, который бы возвращал нужный результат при вызове функций $col.getLink($row()) и $col.isLink($row()).

Я разделил свой код на две части. Файл base.js содержит базовую логику для формирования ссылки, используемой в шаблоне, а файл customer_name.js позволяет настраивать базовую логику формирования ссылки в соответствии с задачами конкретного столбца.

Базовый функционал

В качестве базы я беру существующий UI-компонент column:

define([
    "Magento_Ui/js/grid/columns/column",
    "mageUtils"
], function (Column, utils) {
    ...
}

и (пере)определяю его атрибуты, указывая, что для рендеринга используется шаблон ui/grid/cells/link (из модуля Magento_Ui):

    return Column.extend({
        defaults: {
            /**
             * Replace idAttrName & route in children.
             */
            /* name of the identification attribute */
            idAttrName: "customer_id",
            /* route part to the page */
            route: "/customer/index/edit/id/",
            bodyTmpl: "ui/grid/cells/link"
        }
    });

а затем (пере)определяю методы, используемые в шаблоне.

isLink (ссылку можно сформировать, если данные record содержат атрибут с именем, хранящимся в this.idAttrName):

        isLink: function (record) {
            const result = !!utils.nested(record, this.idAttrName);
            return result;
        }

getLink:

        getLink: function (record) {
            const id = utils.nested(record, this.idAttrName);
            const result = ROOT_URL + this.route + id;
            return result;
        }

Ссылка на карточку клиента

В файле customer_name.js базовый функционал переопределяется таким образом, чтобы формировалась ссылка на карточку клиента "http://.../admin/customer/index/edit/id/..." на основании идентификатора клиента customer_id:

define([
    "Flancer32_GridLink/js/grid/column/link/base"
], function (Column) {
    "use strict";

    return Column.extend({
        defaults: {
            idAttrName: "customer_id",
            route: "/customer/index/edit/id/"
        }
    });
});

Подключение рендерера

Кастомный рендерер подключается к гриду в файле с определением соответствующего UI-компонента. В нашем случае это ./module-sales/view/adminhtml/ui_component/sales_order_grid.xml. В собственном модуле создается файл ./view/adminhtml/ui_component/sales_order_grid.xml в котором переопределяем рендерер для соответствующего столбца:

<listing ...>
    <columns name="sales_order_columns">
        <column name="customer_name"
                component="Vendor_Module/js/grid/column/link/customer_name">
            <settings>
                <visible>true</visible>
            </settings>
        </column>
    </columns>
</listing>

Опция settings/visible нужна для того, чтобы колонка "customer_name" была видима в гриде (по-умолчанию она не видна).

Порядок загрузки

При сборке воедино всех xml-дескрипторов различных частей приложения в Magento (в том числе и описание UI-компонентов) важен порядок обработки дескрипторов, относящихся к одним и тем же компонентам, но находящимся в разных модулях. В нашем случае это ./view/adminhtml/ui_component/sales_order_grid.xml. Если платформа сначала обработает дескриптор из нашего модуля, а потом из sales-модуля, то при слиянии дескрипторов конфигурация sales-модуля заместит нашу конфигурацию в тех местах, где определяются одни и те же атрибуты (так, параметр settings/visible будет равен "false"), хотя рендерер все равно будет использоваться наш (sales-модуль не определяет рендерер для ячейки "Customer Name").

Порядок загрузки прописывается в ./etc/module.xml:

<config ...>
    <module name="Vendor_Module" setup_version="0.1.0">
        <sequence>
            <module name="Magento_Sales"/>
        </sequence>
    </module>
</config>

В этом случае наш модуль будет загружаться после модуля "Magento_Sales" и наши настройки, в случае совпадения с настройками в sales-модуле, заместят настройки sales-модуля.

Резюме

Предоставляемый Magento платформой набор рендереров довольно базовый (например, не нашёл рендерера для целых чисел с выравниванием по правому краю), но создание собственных рендереров может оживить стандартный вид Magento-грида в админке.

Код данной публикации оформлен в виде модуля "mage2_ext_grid_column_renderer".

Автор: flancer

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js