Plugins

Notes

Plugins Limitations:
Plugins can not be used on following:

  • Final methods
  • Final classes
  • Non-public methods
  • Class methods (such as static methods)
  • __construct
  • Virtual types
  • Objects that are instantiated before Magento\Framework\Interception is bootstrapped

Important: plugins can be used on interfaces, abstract classes or parent classes. The plugin methods will be called for any implementation of those abstractions.

The di.xml file in your module declares a plugin for a class object:

<config>
    <type name="{ObservedType}">
      <plugin name="{pluginName}" type="{PluginClassName}" sortOrder="1" disabled="false" />
    </type>
</config>

Before methods

...
    public function beforeXXX(ObserverdType, $argument1, $argument2) {
        return [$argument1, $argument2];
    }
...

After methods

...
    public function afterXXX(ObserverdType, $result, $argument1, $argument2){
        return $result
    }
...

Around methods

...
    public function aroundXXX(ObserverdType, callable $proceed, $argument1, $argument2){
        $result = $proceed($argument1, $argument2));
    }
...

vendor\magento\framework\Interception\Interceptor.php::___callPlugins

Experiments

Plugin A Plugin B Action
sortOrder 10 20
before Before10 Before20
around(first half) Around10 first half Around20 first half
original original dispatch
around(second half) Around10 second half Around20 second half
after After10 After20

The execution flow will be as follows:
Before10
Around10 first half
Before20
Around20 first half
original dispatch
After20
Around20 second half
After10
Around10 second half

etc/di.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="VendorName\TestModule\Model\Attribute">
        <plugin name="get_bar_before_10" type="VendorName\TestModule\Plugin\Before10" sortOrder="10"/>
        <plugin name="get_bar_before_20" type="VendorName\TestModule\Plugin\Before20" sortOrder="20"/>
        <plugin name="get_bar_around_10" type="VendorName\TestModule\Plugin\Around10" sortOrder="10"/>
        <plugin name="get_bar_around_20" type="VendorName\TestModule\Plugin\Around20" sortOrder="20"/>
        <plugin name="get_bar_after_10" type="VendorName\TestModule\Plugin\After10" sortOrder="10"/>
        <plugin name="get_bar_after_20" type="VendorName\TestModule\Plugin\After20" sortOrder="20"/>
    </type>
</config>
<?php
namespace VendorName\TestModule\Model;

class Attribute extends  \Magento\Framework\DataObject
{
    public function setOrderId($value)
    {
        return $this->setData('order_id', $value);
    }

    public function getOrderId()
    {
        return $this->getData('order_id');
    }

    public function setBar($value)
    {
         return $this->setData('bar', $value);
    }

    public function getBar()
    {
        $writer = new \Zend\Log\Writer\Stream(BP . '/var/log/layout_block.xml');
        $logger = new \Zend\Log\Logger();
        $logger->addWriter($writer);
        $logger->info('original');
        return $this->getData('bar');
    }

}
<?php
namespace VendorName\TestModule\Plugin;

use Magento\Framework\Exception\NoSuchEntityException;

class Before10
{
    public function beforeGetBar(\VendorName\TestModule\Model\Attribute $subject, $name = null)
    {
        $writer = new \Zend\Log\Writer\Stream(BP . '/var/log/layout_block.xml');
        $logger = new \Zend\Log\Logger();
        $logger->addWriter($writer);
        $logger->info('before10');
    }
}
<?php
namespace VendorName\TestModule\Plugin;

use Magento\Framework\Exception\NoSuchEntityException;

class Before20
{
    public function beforeGetBar(\VendorName\TestModule\Model\Attribute $subject, $name = null)
    {
        $writer = new \Zend\Log\Writer\Stream(BP . '/var/log/layout_block.xml');
        $logger = new \Zend\Log\Logger();
        $logger->addWriter($writer);
        $logger->info('before20');
    }
}
<?php
namespace VendorName\TestModule\Plugin;

use Magento\Framework\Exception\NoSuchEntityException;

class Around10
{
    public function aroundGetBar(\VendorName\TestModule\Model\Attribute $subject, callable $proceed, $name = null)
    {
        $writer = new \Zend\Log\Writer\Stream(BP . '/var/log/layout_block.xml');
        $logger = new \Zend\Log\Logger();
        $logger->addWriter($writer);
        $logger->info('around10 -- before proceed');

        $result = $proceed();

        $logger->info('around10 -- after proceed');

        return $result;
    }
}
<?php
namespace VendorName\TestModule\Plugin;

use Magento\Framework\Exception\NoSuchEntityException;

class Around20
{
    public function aroundGetBar(\VendorName\TestModule\Model\Attribute $subject, callable $proceed, $name = null)
    {
        $writer = new \Zend\Log\Writer\Stream(BP . '/var/log/layout_block.xml');
        $logger = new \Zend\Log\Logger();
        $logger->addWriter($writer);
        $logger->info('around20 -- before proceed');

        $result = $proceed();

        $logger->info('around20 -- after proceed');

        return $result;

    }
}
<?php
namespace VendorName\TestModule\Plugin;

use Magento\Framework\Exception\NoSuchEntityException;

class After10
{
    public function afterGetBar(\VendorName\TestModule\Model\Attribute $subject, $result)
    {
        $writer = new \Zend\Log\Writer\Stream(BP . '/var/log/layout_block.xml');
        $logger = new \Zend\Log\Logger();
        $logger->addWriter($writer);
        $logger->info('after10');

        return $result;
    }
}
<?php
namespace VendorName\TestModule\Plugin;

use Magento\Framework\Exception\NoSuchEntityException;

class After20
{
    public function afterGetBar(\VendorName\TestModule\Model\Attribute $subject, $result)
    {
        $writer = new \Zend\Log\Writer\Stream(BP . '/var/log/layout_block.xml');
        $logger = new \Zend\Log\Logger();
        $logger->addWriter($writer);
        $logger->info('after20');

        return $result;
    }
}

If we call this function, we will get our log

...
    $attribute = $this->_objectManager->get('VendorName\TestModule\Model\Attribute');
    echo $attribute->getBar();
...

Log file

2019-06-03T04:13:46+00:00 INFO (6): before10
2019-06-03T04:13:46+00:00 INFO (6): around10 -- before proceed
2019-06-03T04:13:46+00:00 INFO (6): before20
2019-06-03T04:13:46+00:00 INFO (6): around20 -- before proceed
2019-06-03T04:13:46+00:00 INFO (6): original
2019-06-03T04:13:46+00:00 INFO (6): after20
2019-06-03T04:13:46+00:00 INFO (6): around20 -- after proceed
2019-06-03T04:13:46+00:00 INFO (6): after10
2019-06-03T04:13:46+00:00 INFO (6): around10 -- after proceed

Practice Tests

You need to make some modifications to an entity before it is saved to the database. Your tool of choice is a plugin.
What are requirements for a plugin? (Multiple Choice)
A. The targeted method or class must not be marked final.
B. The plugin method must begin with the type of the plugin.
C. The plugin class must not inherit the targeted class.
D. The plugin class must not be marked abstract.
E. The plugin class must be specified in di.xml.

Answer A B E


What are valid plugin types:
A. around
B. instead
C. post
D. before
E. after

Answer A D E

Reference

Code: vendor\magento\framework\Interception\Interceptor.php::___callPlugins
Plugins (Interceptors)

I think the ‘Prioritizing plugins’ section of developer guide has error. According to our experiment, after executes before around’s second half.

发表评论

电子邮件地址不会被公开。 必填项已用*标注