Magento 2: plugin avant / autour / après l'interaction


32

Dans Magento 2, lorsque vous créez un plug-in "autour"

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

vous pouvez passer au plugin suivant, aboutissant à l'appel de la méthode d'origine, en appelant / invoquant la $proceedméthode transmise . Il s'agit d'un modèle de conception courant, souvent observé dans les implémentations de middleware PHP Frameworks.

Cependant, cela crée une certaine confusion avec les détails de la mise en œuvre. Plus précisément

Si, outre aroundPluginun objet, un objet / une classe a défini un plugin beforeou un afterplugin, quand est- ce qu'ils se déclenchent par rapport à la chaîne de plugins around?

c'est-à-dire que toutes les méthodes antérieures se déclencheront avant qu'une méthode autour du plugin ne se déclenche? Ou est-ce que les plugins avant ne seront activés qu’avant le déclenchement final de la méthode réelle et réelle ?

Le problème spécifique que je tente de localiser est qu’il me semble impossible d’attacher un plug-in à la méthode d’envoi du contrôleur frontal Magento 2 lorsque Magento est en mode de mise en cache pleine page . Le cache de page complet fonctionne par un plugin around qui n'appelle pas$proceed($response) . J'ai essayé de fouiller dans une partie du code autour de ces plugins et j'ai trouvé difficile de raisonner le système sans savoir comment il est prévu que les plugins fonctionnent.

C'est-à-dire que la description sur la page des documents de développement semble, dans ce cas particulier, être inexacte. Il est difficile de savoir si la documentation est erronée, ou s'il s'agit d'un bogue récemment introduit, s'il s'agit d'un cas périphérique ou si la configuration de mon plugin est incorrecte.

Est-ce que quelqu'un sait, par observation directe ou par connaissance culturelle, comment cette priorisation est censée fonctionner?


Alan, avez-vous une règle de base quand utiliser \closure $proceedvs \callable $proceeddans un plugin? Le document officiel mentionne seulement \callableet ne touche jamais \closure.
thdoan

Réponses:


38

Les plugins sont d'abord triés par ordre de tri, puis par préfixe de méthode.

Exemple: pour une méthode avec 3 plugins (PluginA, PluginB, PluginC) avec les méthodes suivantes et sortOrder:

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

Le flux d'exécution doit être le suivant:

  • PluginA :: beforeDispatch ()
  • PluginB :: beforeDispatch ()
  • PluginB :: aroundDispatch ()
    • PluginC :: beforeDispatch ()
    • PluginC :: aroundDispatch ()
      • Action :: dispatch ()
    • PluginC :: afterDispatch ()
  • PluginB :: afterDispatch ()
  • PluginA :: afterDispatch ()

16

Dans le livre de recettes Magento 2:

S'il existe plusieurs plug-ins qui étendent la même fonction d'origine, ils sont exécutés dans l'ordre suivant:

  • le plugin avant avec le plus bas sortOrder
  • le plugin autour avec le plus bas sortOrder
  • autre avant plugins (du plus bas au plus élevé sortOrder)
  • autres autour des plugins (du plus bas au plus élevé sortOrder)
  • le plugin after avec le plus haut sortOrder
  • autre après plugins (du plus haut au plus bas sortOrder)

1

Pour moi, cela devrait fonctionner comme:

  • si l'ordre de tri n'est pas défini, son équivalent de zéro (et cela signifie que l'ordre réel n'est pas défini)
  • les plugins doivent être triés par ordre

Si vous passez en revue le code de \Magento\Framework\Interception\Interceptor::___callPlugins()vous pouvez voir que les plugins appelés dans l'ordre de stockés dans la $pluginInfovariable. Cette information a été transmise par une méthode générée automatiquement dans des intercepteurs tels que

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

Lorsque vous voyez l' \Magento\Framework\Interception\PluginListInterfaceinterface et l' \Magento\Framework\Interception\PluginList\PluginListimplémentation par défaut responsables du tri des plugins. Voir la méthode _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;
    }
} 

Pour moi cette fonction a deux erreurs logiques:

  • return $itemB['sortOrder'];devrait être return - $itemB['sortOrder'];
  • return 1; devrait être return 0;

J'espère que cela vous aidera.


mais est-ce que $ pluginInfo est entièrement chargé avec les plugins? Ou y a-t-il une charge paresseuse qui pourrait avoir une incidence sur le comportement? Qu'est-ce que l'ordre de tri signifie pour plusieurs plugins? c'est-à-dire "avant le plugin 1, autour du plugin 1, après le plugin 1, avant le plugin 2, autour du plugin 2, après le plugin 2" ou "avant le plugin 1", "avant le plugin 2, autour du plugin1, autour du plugin 2", etc. Le code ressemble à celui-ci, mais "getNext" fournit des informations de plug-in de manière (peut-être?) Paresseuse, et comment Magento évite les récursions en rendant tout cela peu clair, et difficile à repérer.
Alan Storm

Classe de plugin Magento class not plugin method.
KAndy

Et la liste des plugins peut être changée, par exemple, si un nouvel aria nous est chargé.
KAndy

Certaines connaissances implicites que vous possédez ne sont pas évidentes, car "trier la classe du plugin et non la méthode du plugin" n'indique pas clairement quelles sont les règles d'interaction des plugins.
Alan Storm

peut-être que ce lien sera utile magehero.com/posts/472/magento-2-interception
KAndy
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.