DI плагіни в Magento 2

У 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(
'кількість',
'cataloginventory_stock_item',
'кількість',
'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);

Посилання


Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.