Magento 2: Plugin antes / próximo / depois da interação


32

No Magento 2, quando você cria um plug-in "around"

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

você pode prosseguir para o próximo plug-in, culminando em chamar o método original real, chamando / chamando o $proceedmétodo passado . Esse é um padrão de design comum, geralmente visto nas implementações de middleware do PHP Frameworks.

Contudo - apresenta alguma confusão w / r / t aos detalhes da implementação. Especificamente

Se, além de um aroundPlugin, um objeto / classe tem um beforeou afterplugin definido, quando é acionado em relação à cadeia de plugins?

ou seja, todos os métodos anteriores são acionados antes que qualquer método de plug-in em torno seja acionado? Ou será antes plugins única fogo antes da final, reais verdadeira incêndios método?

O problema específico que estou tentando rastrear é que não consigo conectar um plug-in ao método de despacho no controlador frontal do Magento 2 quando o Magento está no modo de cache de página inteira . O cache da página inteira opera por um plug-in que não chama $proceed($response). Eu tentei cavar parte do código em torno desses plugins e achei o sistema difícil de raciocinar sem saber como seus plugins se destinam.

ie - a descrição na página dev docs parece, nesta instância específica, imprecisa. Não está claro se a documentação está incorreta ou se é um bug recentemente introduzido, se é um caso de extrema importância ou se a configuração do meu plugin está errada.

Alguém sabe, por observação direta ou por conhecimento cultural, como essa priorização deve funcionar?


Alan, você tem uma regra de ouro quando usar \closure $proceedvs. \callable $proceedem um plug-in? O documento oficial apenas menciona \callablee nunca toca \closure.
Thdan

Respostas:


38

Os plug-ins são classificados primeiro pela ordem de classificação e depois pelo prefixo do método.

Exemplo: para o método com 3 plugins (PluginA, PluginB, PluginC) com os seguintes métodos e sortOrder:

  • PluginA (sortOrder = 10)
    • beforeDispatch ()
    • afterDispatch ()
  • PluginB (sortOrder = 20)
    • beforeDispatch ()
    • aroundDispatch ()
    • afterDispatch ()
  • PluginC (sortOrder = 30):
    • beforeDispatch ()
    • aroundDispatch ()
    • afterDispatch ()

O fluxo de execução deve ser o seguinte:

  • PluginA :: beforeDispatch ()
  • PluginB :: beforeDispatch ()
  • PluginB :: aroundDispatch ()
    • PluginC :: beforeDispatch ()
    • PluginC :: aroundDispatch ()
      • Ação :: dispatch ()
    • PluginC :: afterDispatch ()
  • PluginB :: afterDispatch ()
  • PluginA :: afterDispatch ()

16

No livro de receitas Magento 2:

Se houver vários plugins que estendem a mesma função original, eles serão executados na seguinte sequência:

  • o plug-in anterior com o menor sortOrder
  • o plugin around com o menor sortOrder
  • outro antes de plugins (do menor para o maior sortOrder)
  • outro em torno de plugins (do menor para o maior sortOrder)
  • o plugin after com o mais alto sortOrder
  • outro após plugins (do mais alto para o mais baixo sortOrder)

1

Para mim, deve funcionar como:

  • se a ordem de classificação não for definida, seu equivalente a zero (e isso significa que a ordem real é indefinida)
  • os plugins devem ser classificados por ordem

Se você revisar o código, \Magento\Framework\Interception\Interceptor::___callPlugins()poderá ver os plug-ins chamados em ordem de armazenados na $pluginInfovariável. Essas informações transmitidas do método gerado automaticamente em interceptores como

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

Como você vê a \Magento\Framework\Interception\PluginListInterfaceinterface e a \Magento\Framework\Interception\PluginList\PluginListimplementação padrão responsáveis ​​pela classificação dos plugins. Consulte o método _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;
    }
} 

Para mim, essa função tem dois erros lógicos:

  • return $itemB['sortOrder'];deveria ser return - $itemB['sortOrder'];
  • return 1; deveria estar return 0;

Espero que ajude você.


mas o $ pluginInfo está totalmente carregado com plugins? Ou há algum carregamento lento que possa afetar o comportamento? O que significa ordem de classificação para vários plugins? ou seja, é "antes do plug-in 1, em torno do plug-in 1, após o plug-in 1, antes do plug-in 2, em torno do plug-in 2, após o plug-in 2" ou "antes do plug-in 1", "antes do plug-in 2, em torno do plug-in1, em torno do plug-in 2", etc. O código se parece com o posterior, mas "getNext" preenche as informações do plug-in de uma maneira preguiçosa de carregamento, e como o Magento evita a recursão por aí torna tudo isso claro e difícil de identificar o que é um bug, o que é um recurso.
Alan Storm

Classe de plugin de classificação Magento, não método de plug-in.
Kandy

E a lista de plugins pode ser alterada, por exemplo, se uma nova ária for carregada.
precisa saber é o seguinte

Você tem algum conhecimento implícito que não é óbvio, porque "classificar a classe do plug-in e não o método do plug-in" não deixa claro quais são ou devem ser as regras para a interação do plug-in.
Alan Storm

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.