📜 ⬆️ ⬇️

DI plugins in Magento 2

In Magento 2, instead of rewrite'ov, used in the first version, appeared plug-ins that allow you to override the behavior of most methods, intercepting the flow of execution in three ways:


More information about plug-ins can be found in the documentation , and under the cut - just an example of use.

Task


For example, for the end user, it is important that the counting of the quantity of products is carried out with reference to a specific warehouse. Suppose a new table is created in the database and the inventory of the quantity of goods in stock is kept in the warehouse_item table, where the primary key is the combination of the warehouse identifier and product identifier:

 CREATE TABLE warehouse_item ( product_id ..., warehouse_id ..., qty ..., PRIMARY KEY (product_id, warehouse_id), ... ) 

Thus, in the admin panel, in the product grid, when outputting, you need to replace the data in the "Quantity" column ( cataloginventory_stock_item.qty ) with their total value SUM(warehouse_item.qty) .
')

When analyzing the existing code, it turned out that the grid is built on the basis of data provided by Magento\Catalog\Ui\DataProvider\Product\ProductDataProvider , and data on the quantity of the product is added to the provider through the DI settings ( 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> 

Here is the code for the AddQuantityFieldToCollection class:

 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' ); } } 

That is, in order for the addField method not to work out and not add to the collection the amount of product from cataloginventory_stock_item , you need to intercept its execution using a plugin using the around method.

Creating a plugin


DI Setup


Register the plugin in the DI configuration of our module ( etc/di.xml or 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> 

Plug code


For the around-interception of the addField method, addField create in the plugin a method aroundAddField that " does nothing ":

 namespace Vendor\Module\Plugin; use Magento\CatalogInventory\Ui\DataProvider\Product\AddQuantityFieldToCollection as Subject; class AddQuantityFieldToCollection { public function aroundAddField(Subject $subject, \Closure $proceed) { return; } } 

Generated class


After clearing the generated files ( ./var/generation/* ) and moving the WebUI Admin to the product grid, the newly created "interceptor" code can be found in the file ./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); } } } 

Call structure



The class generated by Magento 2 is highlighted in orange (the 26th line is ___callPlugins after else), the white one is our own plugin.

Conclusion


From the stektrais it can be seen that DI in Magento 2 replaces classes for which plug-ins are set, generated by a "interceptor", which consistently applies before , after , around "wrappers" for the original methods:

 return $this->___callPlugins('addField', func_get_args(), $pluginInfo); 

and sometimes the original methods themselves:

 return parent::addField($collection, $field, $alias); 

Links


Source: https://habr.com/ru/post/279413/


All Articles