Magento 2 Plugin - Interceptor - Magento 2插件 - 拦截器-插件开发

Magento 2 Plugin - Interceptor - Magento 2插件 - 拦截器


Magento 2 Plugin
 is a technical plugin for your better writing code. Interception Plugin is referred to a little magento 2 extension that allows editing the behavior of any public class or method by intercepting a function call and running code either before or after or around the function call. By using this Magento 2 Plugin Interception, you can modify the behavior of a class while there is no need to change the class directly.

Magento 2插件是一个技术插件,可以更好地编写代码。拦截插件被称为一个小的magento 2扩展,它允许通过在函数调用之前或之后拦截函数调用和运行代码来编辑任何公共类或方法的行为。通过使用此Magento 2插件拦截,您可以修改类的行为,而无需直接更改类。

 

Maybe you still think the observers can help you do that fluently but some differences need to be pointed out. Particularly, not only create functions of a class using dependency injection but Interception plugin can also be confirmed with a sortOrder, that allows checking the chain and order on which plugins run. That is the reason why this plugin doesn’t make the class change and doesn’t have any conflict with one another

 

也许你仍然认为观察者可以帮助你流利地做到这一点,但需要指出一些差异。特别是,不仅使用依赖注入创建类的函数,而且还可以使用sortOrder确认Interception插件,该sortOrder允许检查链接和运行插件的顺序。这就是为什么这个插件不会使类更改并且彼此之间没有任何冲突的原因

1.Magento 2插件的好处

对于像您一样的模块开发人员,Magento 2 Interception插件允许:

  • 转发在对象管理器控制的对象上使用的任何方法调用并采取编程操作
  • 修改在对象管理器控制的对象上使用的任何方法调用的返回值
  • 修改在对象管理器控制的对象上使用的任何方法调用的参数
  • 当其他模块以相同或可预测的方式进行相同方法时,类似地继续进行。

如果您从未有过以这种方式创建系统的经验,那么当您对性能特征感到困惑时,并不奇怪。
但与Mageplaza开发团队合作,他们对专业知识充满信心,知道应该为这项工作应用哪些软件设计模式。
在本主题中,可能会给出很少的拦截器模式,因此如果您需要获取更多信息或本帖子范围内未包含的任何问题,请在此处与我们联系

2.Magento 2插件的限制

什么情况Magento 2 Interception插件无法使用?

  1. 在Magento \ Framework \ Interception之前实例化的对象是自我引导运行的;
  2. 最后的方法;
  3. 最后的类;
  4. 任何包含至少一个最终公共方法的类;
  5. 非 Public 方法(Non-public methods);
  6. 类方法(如静态方法);
  7. __construct;
  8. 虚拟类型(Virtual types);

3.创建Magento 2新插件的指南

  1. 在Magento 2中声明一个插件:
    <config>
        <type name="{ObservedType}">
            <plugin name="{pluginName}" type="{PluginClassName}" sortOrder="1" disabled="false"/>
        </type>
    </config>
    

      解释:
    1.必需的选项:

    type name:输入需要遵循的类或接口的名称。
    plugin name:标识插件的任意插件名称。还用于合并插件的配置。
    plugin type:填写插件类的名称或其虚拟类型。您可以为此字段引用以下命名约定:\Vendor\Module\Plugin\<ModelName>Plugin


    2.可选选项:

    plugin sortOrder:当插件调用进程中的其他相同方法时设置顺序。
    plugin disabled:这允许您快速启用或禁用插件。作为默认配置,所选值为false。使用此属性可禁用di.xml文件中的核心或第三方插件。


    3.如下例所示,我们将编辑 app\code\Mageplaza\HelloWorld\etc\di.xml, 您需要插入代码段:

    <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/ObjectManager/etc/config.xsd">
        <type name="Mageplaza\HelloWorld\Controller\Index\Example">
            <plugin name="Mageplaza_HelloWorld_Plugin" type="Mageplaza\HelloWorld\Plugin\ExamplePlugin" sortOrder="10" disabled="false"  />
        </type>
    </config>
    

      例如,下面的代码定义了类型名称,我们在 app/code/Mageplaza/HelloWorld/Controller/Index/  /创建了Example.php文件

    内容如下:

    <?php
    
    namespace Mageplaza\HelloWorld\Controller\Index;
    
    class Example extends \Magento\Framework\App\Action\Action
    {
    
    	protected $title;
    
    	public function execute()
    	{
    		echo $this->setTitle('Welcome');
    		echo $this->getTitle();
    	}
    
    	public function setTitle($title)
    	{
    		return $this->title = $title;
    	}
    
    	public function getTitle()
    	{
    		return $this->title;
    	}
    }
    

      使用插件名称,我们在 app/code/Mageplaza/HelloWorld/Plugin/ /创建了Example.php文件:

    内容如下:

    <?php
    
    namespace Mageplaza\HelloWorld\Plugin;
    
    class ExamplePlugin{
    
    }
    
  2. 在Magento 2中定义一个插件

    插件是通过在方法之前,之后或周围使用代码来扩展或编辑公共方法行为的好方法。
    首先,请获取一个对象,该对象提供对被观察方法类的所有公共方法的许可。


    插件中的3种方法

    1. before - beforeDispatch()
    2. around - aroundDispatch()
    3. after - afterDispatch()

    1. Before methods:在方法是在观察方法中运行的第一种方法之前,这些方法必须与前面标签 before 的观察名称具有相同的名称。

    要应用before方法来修改观察方法的参数的话,可以返回修改后的参数。如果有多个参数,则返回将根据这些参数的范围执行。如果返回无效,则意味着不应修改被观察方法的参数。如下:

    <?php
    
    namespace Mageplaza\HelloWorld\Plugin;
    
    class ExamplePlugin
    {
    
    	public function beforeSetTitle(\Mageplaza\HelloWorld\Controller\Index\Example $subject, $title)
    	{
    		$title = $title . " to ";
    		echo __METHOD__ . "</br>";
    
    		return [$title];
    	}
    
    }
    

      

    2.After methods:方法在观察到的方法完成后立即开始运行,并且这些方法必须与观察到的名称具有相同的名称,而前缀标签是“after”。

    在方法之后,负责以正确的方式编辑观察方法的结果并且需要具有返回值。如下:
    <?php
    
    namespace Mageplaza\HelloWorld\Plugin;
    
    class ExamplePlugin
    {
    
    	public function afterGetTitle(\Mageplaza\HelloWorld\Controller\Index\Example $subject, $result)
    	{
    
    		echo __METHOD__ . "</br>";
    
    		return '<h1>'. $result . 'Mageplaza.com' .'</h1>';
    
    	}
    
    }
    

      

    3. Around methods(围绕方法):around方法允许代码在observe方法之前和之后运行,因此您可以覆盖方法。这些方法必须与观察到的名称具有相同的名称,而前缀标签为“around”。

    在排列原始方法的参数之前,可以将来自around方法的可调用 callable 到链中的下一个方法,这意味着还会调用下一个插件或观察到的函数。
    注意:如果未声明 callable,则不会调用下一个插件和原始方法。

    <?php
    
    namespace Mageplaza\HelloWorld\Plugin;
    
    class ExamplePlugin
    {
    
    
    	public function aroundGetTitle(\Mageplaza\HelloWorld\Controller\Index\Example $subject, callable $proceed)
    	{
    
    		echo __METHOD__ . " - Before proceed() </br>";
    		 $result = $proceed();
    		echo __METHOD__ . " - After proceed() </br>";
    
    
    		return $result;
    	}
    
    }
    

      
    4. Check the result (检查结果):ExamplePlugin.php的所有内容如下:

    <?php
    
    namespace Mageplaza\HelloWorld\Plugin;
    
    class ExamplePlugin
    {
    
    	public function beforeSetTitle(\Mageplaza\HelloWorld\Controller\Index\Example $subject, $title)
    	{
    		$title = $title . " to ";
    		echo __METHOD__ . "</br>";
    
    		return [$title];
    	}
    
    
    	public function afterGetTitle(\Mageplaza\HelloWorld\Controller\Index\Example $subject, $result)
    	{
    
    		echo __METHOD__ . "</br>";
    
    		return '<h1>'. $result . 'Mageplaza.com' .'</h1>';
    
    	}
    
    
    	public function aroundGetTitle(\Mageplaza\HelloWorld\Controller\Index\Example $subject, callable $proceed)
    	{
    
    		echo __METHOD__ . " - Before proceed() </br>";
    		 $result = $proceed();
    		echo __METHOD__ . " - After proceed() </br>";
    
    
    		return $result;
    	}
    
    }
    

      在此之后,请刷新缓存并检查结果。它会像这样显示出来



    如果您的插件是通过与参数匹配的方法调用的,它也必须与它们匹配,同时,您需要仔细遵循它们。在此过程中,请注意方法的原始签名以及默认参数和建议类型。

    例如,应用以下代码来标识可以为 nullable:的 SomeType  类型的参数:

    <?php
    namespace Mageplaza\HelloWorld\Model;
    
    class MyUtility
    {
        public function save(SomeType $obj = null)
        {
            //do something
        }
    }
    

      
    如果你用下面的插件包装这个方法:

    <?php
    namespace Mageplaza\HelloWorld\Plugin;
    
    class MyUtilityPlugin
    {
        public function aroundSave(\Mageplaza\HelloWorld\Model\MyUtility $subject, \callable $proceed, SomeType $obj)
        {
          //do something
        }
    }
    

      注意: Missing = Null

    如果您将该方法与null一起调用,则PHP会产生致命错误(fatal error),因为您的插件中不允许使用插件null。
    此外,遵循方法调用的插件中的参数非常重要。
    但如果不关心参数,请使用 use the variadics and argument unpacking 来完成此操作:

    <?php
    namespace Mageplaza\HelloWorld\Plugin;
    
    class MyUtilityPlugin
    {
        public function aroundSave(\Mageplaza\HelloWorld\Model\MyUtility $subject, \callable $proceed, ...$args)
        {
          //do something
          $proceed(...$args);
        }
    }
    

      

  3.  Set priority for plugins (设置插件的优先级):

    sortOrder 选项允许 将正在观察相同方法的插件放入队列中。
    当方法开始调用之前,之后或周围时,插件将逐个应用。

4. 插件实例:Visit-访问 https://github.com/mageplaza/magento2-samples/tree/master/sample-module-interception

作者翻译:徐锅
转发请注明来源。
翻译来源:https://www.mageplaza.com/magento-2-module-development/magento-2-plugin-interceptor.html

posted @ 2018-07-05 10:38  徐锅  阅读(1344)  评论(0编辑  收藏  举报