В Magento 2 вместо rewrite’ов, использовавшихся в первой версии, появились плагины, которые позволяют переопределить поведение большинства методов, перехватив поток выполнения тремя способами:
- before
- after
- around
Подробнее про плагины можно узнать в документации, а под катом — просто пример использования.
Задача
Допустим, для конечного пользователя важно, чтобы учет количества продуктов велся с привязкой к конкретному складу. Допустим, в базе создана новая таблица warehouse
и учет количества продукта на складе ведется в таблице warehouse_item
, где первичным ключом является комбинация идентификатора склада и идентификатора продукта:
CREATE TABLE warehouse_item ( product_id ..., warehouse_id ..., qty ..., PRIMARY KEY (product_id, warehouse_id), ... )
Т.о., в админке, в гриде продуктов при выводе нужно заместить данные в столбце "Quantity" (cataloginventory_stock_item.qty
) их суммарным значением SUM(warehouse_item.qty)
.
При анализе существующего кода выяснилось, что грид строится на основании данных, предоставляемых Magento\Catalog\Ui\DataProvider\Product\ProductDataProvider
, а данные по количеству продукта добавляются в провайдер через настройки DI (magento/module-catalog-inventory/etc/adminhtml/di.xml
):
<type name="Magento\Catalog\Ui\DataProvider\Product\ProductDataProvider"> <arguments> <argument name="addFieldStrategies" xsi:type="array"> <item name="qty" xsi:type="object">Magento\CatalogInventory\Ui\DataProvider\Product\AddQuantityFieldToCollection</item> </argument> ... </arguments> </type>
Вот код класса AddQuantityFieldToCollection
:
namespace Magento\CatalogInventory\Ui\DataProvider\Product; ... class AddQuantityFieldToCollection implements AddFieldToCollectionInterface { public function addField(Collection $collection, $field, $alias = null) { $collection->joinField( 'qty', 'cataloginventory_stock_item', 'qty', 'product_id=entity_id', '{{table}}.stock_id=1', 'left' ); } }
Т.е., для того, чтобы метод addField
не отрабатывал и не добавлял к коллекции количество продукта из cataloginventory_stock_item
, нужно перехватить его выполнение при помощи плагина с использованием способа around
.
Создание плагина
Настройка DI
Регистрируем плагин в конфигурации DI нашего модуля (etc/di.xml
или etc/adminhtml/di.xml
):
<?xml version="1.0"?> <config ...> <type name="Magento\CatalogInventory\Ui\DataProvider\Product\AddQuantityFieldToCollection"> <plugin name="vendor_module_plugin" type="Vendor\Module\Plugin\AddQuantityFieldToCollection" sortOrder="100" disabled="false"/> </type> </config>
Код плагина
Для around-перехвата метода addField
создаем в плагине метод aroundAddField
, который "делает ничего":
namespace Vendor\Module\Plugin; use Magento\CatalogInventory\Ui\DataProvider\Product\AddQuantityFieldToCollection as Subject; class AddQuantityFieldToCollection { public function aroundAddField(Subject $subject, \Closure $proceed) { return; } }
Сгенерированный класс
После очистки генерируемых файлов (./var/generation/*
) и перехода чере Admin WebUI в грид продуктов код вновь созданного "перехватчика"" можно найти в файле ./var/generation/Magento/CatalogInventory/Ui/DataProvider/Product/AddQuantityFieldToCollection/Interceptor.php
:
<?php namespace Magento\CatalogInventory\Ui\DataProvider\Product\AddQuantityFieldToCollection; /** * Interceptor class for @see * \Magento\CatalogInventory\Ui\DataProvider\Product\AddQuantityFieldToCollection */ class Interceptor extends \Magento\CatalogInventory\Ui\DataProvider\Product\AddQuantityFieldToCollection implements \Magento\Framework\Interception\InterceptorInterface { use \Magento\Framework\Interception\Interceptor; public function __construct() { $this->___init(); } /** * {@inheritdoc} */ public function addField(\Magento\Framework\Data\Collection $collection, $field, $alias = null) { $pluginInfo = $this->pluginList->getNext($this->subjectType, 'addField'); if (!$pluginInfo) { return parent::addField($collection, $field, $alias); } else { return $this->___callPlugins('addField', func_get_args(), $pluginInfo); } } }
Стектрейс вызовов
Оранжевым подсвечен класс, сгенерированный Magento 2 (26-я строка — это ___callPlugins
после else), белым — наш собственный плагин.
Вывод
Из стектрейса видно, что DI в Magento 2 подменяет классы, для которых заданы плагины, сгенерированным "перехватчиком", который последовательно применяет before
, after
, around
"обертки" для оригинальных методов:
return $this->___callPlugins('addField', func_get_args(), $pluginInfo);
а иногда и сами оригинальные методы:
return parent::addField($collection, $field, $alias);
Ссылки
ссылка на оригинал статьи https://habrahabr.ru/post/279413/
Добавить комментарий