DI plugins in Magento 2

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

    • before
    • after
    • around

    You can find out more about plugins in the documentation , and under the cut is just an example of use.

    Task


    Suppose it is important for the end user that the accounting of the number of products is carried out with reference to a specific warehouse. Suppose a new table has been created in the database warehouseand the quantity of products in the warehouse is kept in a table warehouse_itemwhere the primary key is the combination of the warehouse identifier and the 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 outputing, you need to replace the data in the "Quantity" ( cataloginventory_stock_item.qty) column 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 the data provided Magento\Catalog\Ui\DataProvider\Product\ProductDataProvider, and data on the quantity of the product is added to the provider through the DI ( magento/module-catalog-inventory/etc/adminhtml/di.xml) settings :

    Magento\CatalogInventory\Ui\DataProvider\Product\AddQuantityFieldToCollection
            ...
        

    Here is the class code 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'
            );
        }
    }

    That is, so that the method addFielddoes not work out and does not add the quantity of the product from the collection cataloginventory_stock_item, you need to intercept its execution using the plugin using the method around.

    Plugin creation


    DI setup


    We register the plugin in the DI configuration of our module ( etc/di.xmlor etc/adminhtml/di.xml):


    Plugin code


    For around-interception of the method, addFieldcreate a method in the plugin aroundAddFieldthat " 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 cleaning the generated files ( ./var/generation/*) and switching Admin WebUI to the products grid, the code of the newly created "interceptor" can be found in the file ./var/generation/Magento/CatalogInventory/Ui/DataProvider/Product/AddQuantityFieldToCollection/Interceptor.php:

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

    Stectrace Calls



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

    Conclusion


    From stektreysa seen that the DI in Magento 2 replaces the classes, which are defined plugins generated "interceptor", consistently applied before, after, around"wrapper" for the original methods:

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

    and sometimes the original methods themselves:

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

    References



    Also popular now: