Magento 2:互动之前/前后/之后的插件


32

在Magento 2中,当您创建“周围”插件时

public function aroundRenderResult(
    \Magento\Framework\Controller\ResultInterface $subject,
    \Closure $proceed,
    ResponseHttp $response
) {
    //...
    $proceed($response);
    //...      
}    

您可以继续进行下一个插件,最终通过调用/调用传入的$proceed方法来调用实际的原始方法。这是一种常见的设计模式,通常在PHP Frameworks中间件实现中看到。

但是,它确实给实现细节带来了一些混乱。特别

如果除之外aroundPlugin,对象/类还定义了beforeafter插件,它们何时相对于周围的插件链触发?

即所有之前的方法会在所有周围的插件方法触发之前触发吗?或插件,然后将火最终,实际前实际方法火灾?

我要跟踪的具体问题是,当Magento处于全页缓存模式时,我似乎无法获得与Magento 2前端控制器的调度方法相连的插件。全页缓存由调用的环绕插件操作$proceed($response)。我已经尝试研究这些插件的一些代码,并且发现系统很难在不知道插件打算如何工作的情况下进行推理。

即- 在此特定实例中,开发文档页面上描述似乎不准确。尚不清楚文档是否错误,或者这是最近引入的错误,是否是边缘情况,或者我的插件配置是否错误。

是否有人通过直接观察或文化知识知道这种优先次序应该如何起作用?


艾伦,在插件中使用\closure $proceedvs. 时,您有经验法则\callable $proceed吗?在官方文档只提到\callable,从不触及\closure
thdoan '16

Answers:


38

插件首先按排序顺序排序,然后按方法前缀排序。

示例:适用于具有以下方法和sortOrder的3个插件(PluginA,PluginB,PluginC)的方法:

  • 插件A(sortOrder = 10)
    • beforeDispatch()
    • afterDispatch()
  • PluginB(sortOrder = 20)
    • beforeDispatch()
    • aroundDispatch()
    • afterDispatch()
  • PluginC(sortOrder = 30):
    • beforeDispatch()
    • aroundDispatch()
    • afterDispatch()

执行流程应如下:

  • 插件A :: beforeDispatch()
  • 插件B :: beforeDispatch()
  • 插件B :: aroundDispatch()
    • 插件C :: beforeDispatch()
    • 插件C :: aroundDispatch()
      • 行动:: dispatch()
    • 插件C :: afterDispatch()
  • 插件B :: afterDispatch()
  • 插件A :: afterDispatch()

16

从Magento 2食谱中:

如果有多个扩展相同原始功能的插件,则按以下顺序执行:

  • 最低之前的插件 sortOrder
  • 最低的环绕插件 sortOrder
  • 其他之前的插件(从最低到最高sortOrder
  • 其他周围的插件(从最低到最高sortOrder
  • 最高的after插件 sortOrder
  • 之后的其他插件(从最高到最低sortOrder

1

对我来说,它应该作为:

  • 如果未定义排序顺序,则它等于零(这意味着未定义实际顺序)
  • 插件应按顺序排序

如果查看代码,则\Magento\Framework\Interception\Interceptor::___callPlugins()可以看到按存储的顺序调用了插件$pluginInfo。此信息是通过拦截器等自动生成的方法传递的

public function {method}()
{
    $pluginInfo = $this->pluginList->getNext($this->subjectType, '{method}');
    if (!$pluginInfo) {
        return parent::{method}();
    } else {
        return $this->___callPlugins('{method}', func_get_args(), $pluginInfo);
    }
}

如您所见\Magento\Framework\Interception\PluginListInterface\Magento\Framework\Interception\PluginList\PluginList负责插件排序的接口和默认实现。参见_inheritPlugins:152方法

/**
 * Sort items
 *
 * @param array $itemA
 * @param array $itemB
 * @return int
 */
protected function _sort($itemA, $itemB)
{
    if (isset($itemA['sortOrder'])) {
        if (isset($itemB['sortOrder'])) {
            return $itemA['sortOrder'] - $itemB['sortOrder'];
        }
        return $itemA['sortOrder'];
    } elseif (isset($itemB['sortOrder'])) {
        return $itemB['sortOrder'];
    } else {
        return 1;
    }
} 

对我来说,此功能有两个逻辑错误:

  • return $itemB['sortOrder'];应该是return - $itemB['sortOrder'];
  • return 1; 应该 return 0;

希望对您有帮助。


但是$ pluginInfo是否已满载插件?还是正在进行一些可能会影响行为的延迟加载?排序顺序对多个插件意味着什么?即是“在插件1之前,在插件1周围,在插件1之后,在插件2之前,在插件2附近,在插件2之后,还是在”在插件1之前”,“在插件2之前,在插件1周围,在插件2周围”等等。代码看起来像后来的代码,但是“ getNext”以(可能是?)延迟加载的方式填充了插件信息,并且Magento如何避免前后递归使所有这些变得不清楚,并且很难发现什么是bug,什么是功能。
艾伦·风暴

Magento排序插件类而不是插件方法。
康迪

插件列表可以更改,例如,如果我们加载了新的咏叹调。
康迪

您所掌握的一些隐性知识并不明显,因为“对插件类而不是插件方法进行排序”并不能使插件交互的规则明确。
艾伦·风暴

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.