Magento 2: Plugin vor / um / nach Interaktion


32

In Magento 2, wenn Sie ein "Around" -Plugin erstellen

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

Sie können mit dem nächsten Plugin fortfahren und die eigentliche ursprüngliche Methode aufrufen, indem Sie die übergebene $proceedMethode aufrufen / aufrufen . Dies ist ein häufig vorkommendes Entwurfsmuster, das häufig in Middleware-Implementierungen von PHP Frameworks auftritt.

Es gibt jedoch einige Verwirrung hinsichtlich der Implementierungsdetails. Speziell

Wenn für ein aroundPluginObjekt / eine Klasse zusätzlich zu einem ein beforeoder ein afterPlugin definiert wurde, wann werden sie in Bezug auf die Kette um Plugins ausgelöst?

dh werden alle Before-Methoden ausgelöst, bevor irgendwelche Around-Plugin-Methoden ausgelöst werden? Oder werden vor Plugins nur vor der endgültigen, tatsächlichen realen Methode ausgelöst?

Das spezifische Problem, das ich aufzuspüren versuche, ist, dass ich anscheinend kein Plugin an die Versandmethode eines Magento 2 Front-Controllers anhängen kann, wenn sich Magento im Ganzseiten-Caching-Modus befindet . Der Ganzseiten-Cache wird von einem Around-Plugin betrieben, das nicht aufgerufen wird $proceed($response). Ich habe versucht, einen Teil des Codes um diese Plugins herum zu studieren, und es fiel mir schwer, über das System nachzudenken, ohne zu wissen, wie es funktionieren soll.

dh - die Beschreibung auf der Seite dev docs scheint in diesem speziellen Fall ungenau zu sein. Es ist unklar, ob die Dokumentation falsch ist oder ob es sich um einen kürzlich eingeführten Fehler handelt, ob es sich um einen Randfall handelt oder ob meine Plugin-Konfiguration falsch ist.

Weiß jemand, durch direkte Beobachtung oder durch kulturelles Wissen, wie diese Priorisierung funktionieren soll?


Alan, hast du eine Faustregel, wann du \closure $proceedvs. \callable $proceedin einem Plugin verwenden sollst ? Das offizielle Dokument erwähnt nur \callableund berührt nie \closure.
Donnerstag,

Antworten:


38

Plugins werden zuerst nach der Sortierreihenfolge und dann nach dem Methodenpräfix sortiert.

Beispiel: für Methode mit 3 Plugins (PluginA, PluginB, PluginC) mit folgenden Methoden und sortOrder:

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

Der Ausführungsablauf sollte folgendermaßen aussehen:

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

16

Aus dem Magento 2-Kochbuch:

Wenn es mehrere Plugins gibt, die dieselbe ursprüngliche Funktion erweitern, werden sie in der folgenden Reihenfolge ausgeführt:

  • das vorher Plugin mit dem niedrigsten sortOrder
  • das um plugin mit dem niedrigsten sortOrder
  • andere vor Plugins (vom niedrigsten zum höchsten sortOrder)
  • Sonstige Plugins (vom niedrigsten zum höchsten sortOrder)
  • das after plugin mit dem höchsten sortOrder
  • andere nach Plugins (vom höchsten zum niedrigsten sortOrder)

1

Für mich sollte es funktionieren als:

  • Wenn die Sortierreihenfolge nicht definiert ist, entspricht sie null (und dies bedeutet, dass die reale Reihenfolge undefiniert ist).
  • Plugins sollten nach Reihenfolge sortiert sein

Wenn Sie den Code von überprüfen, sehen \Magento\Framework\Interception\Interceptor::___callPlugins()Sie, dass die Plugins in der Reihenfolge aufgerufen werden, in der sie in der $pluginInfoVariablen gespeichert sind. Diese Informationen wurden von automatisch generierten Methoden in Interceptors wie z

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

Wie Sie sehen, sind die \Magento\Framework\Interception\PluginListInterfaceBenutzeroberfläche und die \Magento\Framework\Interception\PluginList\PluginListStandardimplementierung für die Sortierung der Plugins verantwortlich. Siehe _inheritPlugins: 152- Methode

/**
 * 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;
    }
} 

Für mich hat diese Funktion zwei logische Fehler:

  • return $itemB['sortOrder'];sollte sein return - $itemB['sortOrder'];
  • return 1; sollte sein return 0;

Hoffe es wird dir helfen.


Aber ist $ pluginInfo voll mit Plugins geladen? Oder wird faul geladen, was sich auf das Verhalten auswirken könnte? Was bedeutet die Sortierreihenfolge für mehrere Plugins? dh ist es "vor Plugin 1, um Plugin 1, nach Plugin 1, vor Plugin 2, um Plugin 2, nach Plugin 2" oder "vor Plugin 1", "vor Plugin 2, um Plugin 1, um Plugin 2" usw. Der Code sieht aus wie der spätere, aber "getNext" füllt die Plug-in-Informationen auf (vielleicht?) Träge Art und Weise, und wie Magento eine Rekursion mit "around" vermeidet, macht dies alles unklar und es ist schwer zu erkennen, was ein Fehler ist, was eine Funktion ist.
Alan Storm

Magento Sort Plugin Klasse nicht Plugin Methode.
KAndy

Und die Liste der Plugins kann zum Beispiel geändert werden, wenn neue Arien geladen werden.
KAndy

Es gibt implizite Kenntnisse, die nicht offensichtlich sind, da "die Plugin-Klasse und nicht die Plugin-Methode sortieren" nicht klar macht, welche Regeln für die Plugin-Interaktion gelten oder gelten sollen.
Alan Storm

Vielleicht ist dieser Link hilfreich. magehero.com/posts/472/magento-2-interception
KAndy
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.