Magento 2: Plugin prima / intorno / dopo l'interazione


32

In Magento 2, quando crei un plugin "around"

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

puoi passare al prossimo plug-in intorno, che termina con la chiamata del metodo originale effettivo, chiamando / invocando il $proceedmetodo passato . Questo è un modello di progettazione comune, spesso visto nelle implementazioni del middleware di PHP Frameworks.

Tuttavia, presenta un po 'di confusione nei dettagli dell'implementazione. In particolare

Se, oltre a aroundPlugin, un oggetto / classe ha un beforeo un afterplugin definito, quando si attivano in relazione alla catena dei plugin intorno?

vale a dire che tutti i metodi precedenti verranno attivati ​​prima che vengano attivati ​​i metodi plug-in intorno? O prima che i plugin si attivino solo prima che venga attivato l'ultimo metodo reale ?

Il problema specifico che sto cercando di rintracciare è che non riesco a ottenere un plug-in collegato al metodo di spedizione un front controller Magento 2 quando Magento è in modalità cache a pagina intera . L'intera cache della pagina funziona con un plugin around che non chiama $proceed($response). Ho provato a scavare in alcuni dei codici attorno a questi plugin e ho trovato il sistema difficile da ragionare senza sapere come funzionassero i plugin.

vale a dire - la descrizione nella pagina dei documenti di sviluppo appare, in questo caso specifico, inaccurata. Non è chiaro se la documentazione sia errata o se si tratta di un bug introdotto di recente, se si tratta di un caso limite o se la mia configurazione del plugin è errata.

Qualcuno sa, per osservazione diretta o per conoscenza culturale, come dovrebbe funzionare questa definizione delle priorità?


Alan, hai una regola empirica quando usare \closure $proceedvs. \callable $proceedin un plugin? Il documento ufficiale menziona solo \callablee non tocca mai \closure.
thdoan

Risposte:


38

I plug-in vengono ordinati prima in base all'ordinamento, quindi in base al prefisso del metodo.

Esempio: per metodo con 3 plugin (PluginA, PluginB, PluginC) con i seguenti metodi e ordinamento:

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

Il flusso di esecuzione dovrebbe essere il seguente:

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

16

Dal libro di cucina di Magento 2:

Se esistono più plugin che estendono la stessa funzione originale, vengono eseguiti nella seguente sequenza:

  • il plugin prima con il più basso sortOrder
  • il plugin around con il più basso sortOrder
  • altri plug-in precedenti (dal più basso al più alto sortOrder)
  • altri intorno ai plugin (dal più basso al più alto sortOrder)
  • il plug-in after con il massimo sortOrder
  • altri plugin dopo (dal più alto al più basso sortOrder)

1

Per me dovrebbe funzionare come:

  • se l'ordinamento non è definito l'equivalente di zero (e questo significa che l'ordine reale non è definito)
  • i plugin dovrebbero essere ordinati per ordine

Se rivedi il tuo codice \Magento\Framework\Interception\Interceptor::___callPlugins()puoi vedere che i plugin vengono chiamati in ordine di memorizzazione nella $pluginInfovariabile. Queste informazioni sono passate dal metodo generato automaticamente in intercettori come

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

Come vedi l' \Magento\Framework\Interception\PluginListInterfaceinterfaccia e l' \Magento\Framework\Interception\PluginList\PluginListimplementazione predefinita sono responsabili dell'ordinamento dei plugin. Vedi _inheritPlugins: metodo 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;
    }
} 

Per me questa funzione ha due errori logici:

  • return $itemB['sortOrder'];dovrebbe essere return - $itemB['sortOrder'];
  • return 1; dovrebbe essere return 0;

Spero che ti possa aiutare.


ma $ pluginInfo è completamente caricato con plugin? O è in corso un caricamento lento che potrebbe influire sul comportamento? Che cosa significa ordinamento per più plugin? vale a dire "prima del plug-in 1, intorno al plug-in 1, dopo il plug-in 1, prima del plug-in 2, intorno al plug-in 2, dopo il plug-in 2" o "prima del plug-in 1", "prima del plug-in 2, intorno al plug-in 1, intorno al plug-in 2", ecc. Il codice è simile al successivo, ma "getNext" popola le informazioni del plug-in in un modo di caricamento (forse?) Pigro, e come Magento evita la ricorsione con around rende tutto ciò poco chiaro e difficile da individuare cosa sia un bug, che cos'è una funzionalità.
Alan Storm,

Classe di plugin di ordinamento Magento non metodo di plugin.
KAndy,

E l'elenco dei plugin può essere modificato, ad esempio, se viene caricata una nuova aria.
KAndy,

C'è qualche conoscenza implicita che hai che non è ovvio, perché "ordinare la classe del plugin e non il metodo del plugin" non chiarisce quali sono o dovrebbero essere le regole per l'interazione con i plugin.
Alan Storm,

forse questo link sarà utile magehero.com/posts/472/magento-2-interception
KAndy
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.