M2 preference和plugin的使用

3.73K 浏览M2交流区

M2 preference和plugin的使用

preference类似于Magento 1中的类重写,等同于说用B类重写A类,我们可以在B类上添加或修改。每当任何类请求类A的实例时,它将随类B实例一起提供。在这里,B类是A类的重写类。基本上,B类包括A类的业务逻辑,可以对其进行扩展或修改。
在di.xml中进行配置,下面是重写MagentoCheckoutControllerOnepageFailure的实例:
在di.xml中声明preference
<!--preference(重写前的类);type(重写后的类)-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <preference for="MagentoCheckoutControllerOnepageFailure" type="vendorNameCheckoutControllerOnepageFailure" />
</config>
<?php

namespace vendorNameCheckoutControllerOnepage;

class Failure extends MagentoCheckoutControllerOnepageFailure
{
    
}

plugin是Magento 2中新引入的允许我们在插入该类的任何公共方法之前之后周围执行我们的代码,我们的plugin会钩入。plugin不会覆盖该类。相反,它挂接到我们要修改业务逻辑的类的各个方法中。plugin通常会避免在覆盖类时出现的冲突。

什么情况Magento 2 Interception插 plugin无法使用?
  • 在Magento Framework Interception之前实例化的对象是自我引导运行的;
  • 最后的方法;
  • 最后的类;
  • 任何包含至少一个最终公共方法的类;
  • 非 Public 方法(Non-public methods);
  • 类方法(如静态方法);
  • __construct;
  • 虚拟类型(Virtual types);
在 di.xml中声明一个plugin
<config>
    <type name="{ObservedType}">
        <plugin name="{pluginName}" type="{PluginClassName}" sortOrder="1" disabled="false"/>
    </type>
</config>
必需的选项:
type name:输入需要遵循的类或接口的名称。
plugin name:标识plugin的任意plugin名称。还用于合并plugin的配置。
plugin type:填写plugin类的名称或其虚拟类型。您可以为此字段引用以下命名约定:VendorModulePlugin<ModelName>Plugin。
可选选项:
plugin sortOrder:当plugin调用进程中的其他相同方法时设置顺序。
plugin disabled:这允许您快速启用或禁用plugin。作为默认配置,所选值为false。使用此属性可禁用di.xml文件中的核心或第三方plugin。
plugin中的3种方法:
1. before - beforeDispatch()   --在观察到的方法开始之前运行,并且这些方法必须与观察到的名称具有相同的名称,而前缀标签是“before”
2. around - aroundDispatch() --around方法允许代码在observe方法之前和之后运行,因此您可以覆盖方法。这些方法必须与观察到的名称具有相同的名称,而前缀标签为“around”
3. after - afterDispatch() --在观察到的方法完成后立即开始运行,并且这些方法必须与观察到的名称具有相同的名称,而前缀标签是“after”
如下例所示,我们将编辑 appcodeSamaryHelloWorldetcdi.xml, 定义一个plugin
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/ObjectManager/etc/config.xsd">
    <type name="SamaryHelloWorldControllerIndexExample">
        <plugin name="Samary_HelloWorld_Plugin" type="SamaryHelloWorldPluginExamplePlugin" sortOrder="10" disabled="false"  />
    </type>
</config>
例如,下面的代码定义了类型名称,我们在 app/code/Samary/HelloWorld/Controller/Index/  /创建了Example.php文件
<?php
 
namespace SamaryHelloWorldControllerIndex;
 
class Example extends MagentoFrameworkAppActionAction
{
 
    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;
    }
}
使用plugin名称,我们在 app/code/Samary/HelloWorld/Plugin/ 创建了Example.php文件:
<?php
 
namespace SamaryHelloWorldPlugin;
 
class ExamplePlugin
{
 
    public function beforeSetTitle(SamaryHelloWorldControllerIndexExample $subject, $title)
    {
        $title = $title . " to ";
        echo __METHOD__ . "</br>";
 
        return [$title];
    }
    
    public function afterGetTitle(SamaryHelloWorldControllerIndexExample $subject, $result)
    {
 
        echo __METHOD__ . "</br>";
 
        return '<h1>'. $result . 'samary.cn' .'</h1>';
 
    }
    
    public function aroundGetTitle(SamaryHelloWorldControllerIndexExample $subject, callable $proceed)
    {
 
        echo __METHOD__ . " - Before proceed() </br>";
         $result = $proceed();
        echo __METHOD__ . " - After proceed() </br>";
 
 
        return $result;
    }
 
}
区别:
plugin是一个类,它通过拦截函数调用并在该函数调用之前,之后或周围运行代码来修改公共类函数的行为。这使您可以替换或扩展任何类或接口的原始公共方法的行为。这种拦截方法减少了扩展之间的冲突,这些扩展改变了相同类或方法的行为。您的Plugin类实现会更改类函数的行为,但不会更改类本身。Magento根据配置的排序顺序依次调用这些拦截器,因此它们不会相互冲突。
preference用于覆盖类.
注:plugin比preference更方便,除非有必要,否则应该在需要时选择使用plugin。

3