Magento 2: Плагін до / навколо / після взаємодії


32

У Magento 2, коли ви створюєте плагін "навколо"

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

ви можете перейти до наступного плагіна, що завершився викликом фактичного оригінального методу, зателефонувавши / викликаючи переданий $proceedметод. Це загальна модель дизайну, часто зустрічається в реалізаціях проміжного програмного забезпечення PHP Frameworks.

Однак - це дійсно представляє певну плутанину з деталями щодо впровадження. Конкретно

Якщо на додаток до aroundPluginоб'єкта / класу визначено beforeабо afterплагін, коли вони запускаються стосовно ланцюга навколо плагінів?

тобто чи будуть усі попередні методи запускатись перед будь-якими методами навколо плагіна? Або перед плагінами буде запущено лише перед остаточним, реальним реальним методом?

Конкретна проблема, яку я намагаюсь знайти, я не можу отримати плагін, приєднаний до методу відправки, передній контролер Magento 2, коли Magento перебуває в режимі кешування на повній сторінці . Повний кеш сторінки керує плагіном навколо, який не викликає $proceed($response). Я спробував зануритися в якийсь код навколо цих плагінів, і мені стало важко міркувати про систему, не знаючи, як вона призначена для роботи плагінів.

тобто - опис на сторінці "Документи розробників" , в цьому конкретному випадку, є неточним. Незрозуміло, чи документація неправильна, чи це нещодавно введена помилка, чи це кращий випадок, чи моя конфігурація плагіна неправильна.

Хтось знає, шляхом прямого спостереження чи культурних знань, як ця пріоритетність повинна працювати?


Алан, у вас є правило, коли використовувати \closure $proceedпроти \callable $proceedплагіна? Офіційний документ тільки згадує \callableі ніколи не зачіпає \closure.
thoan

Відповіді:


38

Плагіни сортуються спочатку за порядком сортування, а потім за префіксом методу.

Приклад: для методу з 3 плагінами (PluginA, PluginB, PluginC) з наступними методами та sortOrder:

  • ПлагінA (sortOrder = 10)
    • beforeDispatch ()
    • afterDispatch ()
  • ПлагінB (sortOrder = 20)
    • beforeDispatch ()
    • навколоDispatch ()
    • afterDispatch ()
  • PluginC (sortOrder = 30):
    • beforeDispatch ()
    • навколоDispatch ()
    • afterDispatch ()

Потік виконання повинен бути наступним:

  • ПлагінA :: beforeDispatch ()
  • ПлагінB :: beforeDispatch ()
  • ПлагінB :: aroundDispatch ()
    • PluginC :: beforeDispatch ()
    • PluginC :: aroundDispatch ()
      • Дія :: відправлення ()
    • PluginC :: afterDispatch ()
  • ПлагінB :: afterDispatch ()
  • ПлагінA :: afterDispatch ()

16

З кулінарної книги Magento 2:

Якщо є кілька плагінів, які розширюють одну і ту ж оригінальну функцію, вони виконуються у такій послідовності:

  • плагін раніше з найнижчим sortOrder
  • плагін навколо з найнижчим sortOrder
  • інші перед плагінами (від найнижчого до найвищого sortOrder)
  • інші навколо плагінів (від найнижчого до найвищого sortOrder)
  • плагін after з найвищим sortOrder
  • інші після плагінів (від найвищого до найнижчого sortOrder)

1

Для мене це має працювати так:

  • якщо порядок сортування не визначений, його еквівалент нульовий (а це означає, що реальний порядок не визначений)
  • плагіни повинні бути впорядковані за порядком

Якщо ви переглянете код, \Magento\Framework\Interception\Interceptor::___callPlugins()ви побачите, що плагіни викликаються в порядку збереження в $pluginInfoзмінній. Ця інформація передала форму автоматично створеного методу в перехоплювачах

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

Як ви бачите, \Magento\Framework\Interception\PluginListInterfaceінтерфейс та \Magento\Framework\Interception\PluginList\PluginListреалізація за замовчуванням відповідають за сортування плагінів. Див _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;
    }
} 

Для мене ця функція має дві логічні помилки:

  • return $itemB['sortOrder'];повинно бути return - $itemB['sortOrder'];
  • return 1; має бути return 0;

Сподіваюся, це допоможе вам.


але чи $ pluginInfo повністю завантажений плагінами? Або відбувається деяке ледаче навантаження, яке може вплинути на поведінку? Що означає порядок сортування для кількох плагінів? тобто "перед плагіном 1, навколо плагіна 1, після плагіна 1, перед плагіном 2, навколо плагіна 2, після плагіна 2" або "перед плагіном 1", "перед плагіном 2, навколо плагіна 1, навколо плагіна 2" і т.д. Код виглядає як пізніше, але "getNext", що заповнює інформацію плагінів (може бути?) Ледачим способом завантаження, і як Magento уникає рекурсії з навколо, це робить все незрозумілим, і важко визначити, що таке помилка, яка особливість.
Алан Шторм

Метод сортування плагіна Magento не метод плагіна.
Кенді

І список плагінів можна змінити, наприклад, якщо нові арії ми завантажимо.
Кенді

У вас є кілька неявних знань, що це не очевидно, тому що "сортувати клас плагінів, а не метод плагіна" не дає зрозуміти, якими правилами взаємодії плагіни є чи повинні бути.
Алан Шторм

можливо, це посилання стане в нагоді magehero.com/posts/472/magento-2-interception
KAndy
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.