Magento 2 - Объяснение плагина и основной код magento


Я создавал свои собственные плагины в Magento 2, однако мне трудно понять ссылки на библиотеки ядра Magento. Допустим, у меня есть плагин, подобный приведенному ниже, почему мы знаем, что GetName находится в этом каталоге \ Magento\Каталог\Модель\Продукт) и откуда мы знаем, что для этого требуется $product, $name?

Если бы я хотел изменить цену продукта, как бы я узнал, в какую библиотеку звонить? Угадываю ли я имя функции GetPrice или есть способ, чтобы иметь возможность чтобы точно знать название функции, которую я хочу изменить, чтобы создать плагин?

  <?php

 namespace Inchoo\Custom\Plugins;

 Class AfterProduct {
 public function afterGetName(\Magento\Catalog\Model\Product $product, 
 $name){

  $price = $product ->getData('price');
  if ($price < 60 ) {
    $name .= " -> cheap" ;
}
  else {
    $name .= " -> expensive";
}
  return $name;
    }
}
Author: Greg, 2018-09-10

2 answers

Во-первых, взгляните на этот метод Magento\Framework\Interception\Interceptor::___callPlugins. Именно здесь происходит волшебство. (Я объясню, почему вам нужно взглянуть на это позже).
Обратите внимание, что Magento\Framework\Interception\Interceptor является признаком , а не классом. Таким образом, $this внутри признака ссылается на объект, обладающий этим признаком.
Этот метод принимает 3 параметра.

  • подключаемый метод,
  • аргументы исходного метода
  • некоторая информация о плагине.

Этот метод определяет переменную (то есть функцию), которая делает это.

if (isset($currentPluginInfo[DefinitionInterface::LISTENER_BEFORE])) {

Проверяет, есть ли у метода before плагины. если это так, он проходит через все объявленные плагины. (foreach ($currentPluginInfo[DefinitionInterface::LISTENER_BEFORE] as $code) {) . и вызывает beforeOriginalMethod (сам плагин), который получает в качестве параметра подключаемый класс ($this) и аргументы исходного метода

Затем он проверяет наличие around плагинов (if (isset($currentPluginInfo[DefinitionInterface::LISTENER_AROUND])) {), аналогичных плагинам before.
Разница в том, что метод плагина получает дополнительный параметр $next, который а callable переменная (функция), определенная выше. это используется для вызова исходного метода внутри плагина around, поскольку плагин around заменяет исходный метод.

Затем он проверяет наличие after плагинов (if (isset($currentPluginInfo[DefinitionInterface::LISTENER_AFTER])) {) это очень похоже на плагины before. Разница в том, что при этом в качестве параметров также принимается результат исходного метода.

Что должны возвращать плагины.

  • before Этот плагин полезен, если вы хотите измените аргументы исходного метода. Поэтому он должен возвращать массив с новыми значениями аргументов. Например, если вы подключаете метод setName из модели продукта, он получает в качестве параметра строку с именем $name. Ваш плагин должен возвращать массив со строкой [$name]. Этот тип плагина может возвращать значение null. Это означает, что исходный метод получит параметры без изменений.
  • around должен возвращать то же самое, что и исходный метод. есть тоже подвох. Если вы не вызовете внутри своего плагина исходный метод (второй параметр, описанный выше), все остальные плагины, которые появятся после вашего, будут проигнорированы.
  • после. Должен возвращать то же самое, что и исходный метод.

Как происходит волшебство.

При создании экземпляра класса через ObjectManager magento проверяет, есть ли у этого класса методы pluginizable (скажем, в 3 раза быстрее: D). Смотрите здесь, какие методы/классы поддерживают плагины.

Короче говоря, он читает файлы di.xml, проверяет наличие объявленных плагинов в классе, который он пытается создать, проверяет, есть ли у классов, объявленных как плагины, методы, которые начинаются с before, after, around и это соответствует именам общедоступных методов класса, который он пытается создать.

Если он что-то находит, он создает класс, который расширяет исходный класс, и он называется Original\ClassName\Interceptor (добавляет interceptor в конце.) и создает экземпляр этого класса вместо исходного один.
Просто найдите в папке generated файл с именем Interceptor.php.

Все эти классы выглядят одинаково.
У них есть черта \Magento\Framework\Interception\Interceptor;, которую я описал выше.

Конструктор такой же, как и исходный конструктор класса с дополнительным вызовом ___init(), который находится в черте \Magento\Framework\Interception\Interceptor.

Затем перечислены все подключаемые методы, и все они выглядят одинаково

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

Вот как создается ссылка из плагинов на реальные классы. Через дочерний класс исходного класса, который либо вызывает исходный метод класса, либо плагины, объявленные для этого класса.

 6
Author: Marius, 2018-09-10 14:36:29

Возможно, вы добавили di.xml файл.

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Catalog\Model\Product">
        <plugin name="plugin_update_product_name" type="Inchoo\Custom\Plugins\AfterProduct"></plugin>
    </type>
</config>

В приведенном выше di.xml файл, имя которого мы объявили="Magento\Каталог\Модель\Продукт", относится к классу, метод которого мы собираемся переопределить.

Таким образом, вы можете найти все связанные методы, которые вы можете использовать, перейдя в magento_rootdirectory/vendor/module-catalog/Model/Product.php файл.

Надеюсь, это поможет.

 4
Author: Rahul Makwana, 2018-09-11 07:29:54