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 Storm
la source
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 ()
Anton Kril
la source
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)
Raphael au pianisme numérique
la source
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.

KAndy
la source
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