В Magento 2 вместо rewrite'ов, использовавшихся в первой версии, появились плагины, которые позволяют переопределить поведение большинства методов, перехватив поток выполнения тремя способами:
Подробнее про плагины можно узнать в документации, а под катом — просто пример использования.
Допустим, для конечного пользователя важно, чтобы учет количества продуктов велся с привязкой к конкретному складу. Допустим, в базе создана новая таблица
Т.о., в админке, в гриде продуктов при выводе нужно заместить данные в столбце "Quantity" (

При анализе существующего кода выяснилось, что грид строится на основании данных, предоставляемых
Вот код класса
Т.е., для того, чтобы метод
Регистрируем плагин в конфигурации DI нашего модуля (
Для around-перехвата метода
После очистки генерируемых файлов (

Оранжевым подсвечен класс, сгенерированный Magento 2 (26-я строка — это
Из стектрейса видно, что DI в Magento 2 подменяет классы, для которых заданы плагины, сгенерированным "перехватчиком", который последовательно применяет
а иногда и сами оригинальные методы:
- 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);