{ Hello Magento 2 }

解决 Magento 2 应用问题,更注重深度挖掘。(ง •̀_•́)ง

0%

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:

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

Before methods

1
2
3
4
5
...
public function beforeXXX(ObserverdType, $argument1, $argument2) {
return [$argument1, $argument2];
}
...

After methods

1
2
3
4
5
...
public function afterXXX(ObserverdType, $result, $argument1, $argument2){
return $result
}
...

Around methods

1
2
3
4
5
...
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

1
2
3
4
5
6
7
8
9
10
11
<?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>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?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');
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?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');
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?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');
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?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;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?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;

}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?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;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?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

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

Log file

1
2
3
4
5
6
7
8
9
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.