Как Magento2 генерирует конкретные ExtensionFactory и ExtensionAttributeInterface?


28

Я хотел бы обернуть голову, используя атрибуты расширения, например, для элементов цитаты.
Нет проблем с добавлением пользовательского атрибута к такой сущности с помощью класса установки, как в Magento 1, это не то, о чем этот вопрос.
В тот момент магия поражает меня, когда я хочу выставить такой атрибут, который был добавлен расширением через API сущностей в качестве атрибута расширения.

ОБНОВЛЕНИЕ : я знаю, как создаются обычные фабрики. Этот вопрос касается специальных фабрик, которые создают экземпляры сгенерированных реализаций для созданных интерфейсов атрибутов расширения.

Вот шаги, которые я предпринимаю, чтобы заставить его работать. Я добавляю их, чтобы те, кто пытается ответить, не должны вдаваться в подробности.
Мой вопрос, КАК или ПОЧЕМУ это работает.

Шаги для предоставления атрибута расширения через API объекта:

  1. Создайте объект, etc/extension_attributes.xmlкоторый добавляет атрибут в интерфейс объекта.
  2. Создайте плагин для добавления значения атрибута к ExtensionAttributesэкземпляру лица .

Для выполнения второго пункта ExtensionAttributesнеобходим экземпляр сущностей . По этой причине плагин зависит от фабрики, которую менеджер объектов поставляет через DI.

Для примера цитаты Magento\Quote\Api\Data\CartItemExtensionFactoryдолжен использоваться пример .
Я думаю, что тип этой фабрики как-то должен быть триггером для магии поколения.

Затем Magento генерирует соответствующий интерфейс \Magento\Quote\Api\Data\CartItemExtensionInterfaceс установщиками и получателями для всех атрибутов расширения.
Тем не менее, кажется, не генерировать конкретную реализацию для этого интерфейса. В аренду PHPStorm этого не видит.

Как Magento собирает информацию, необходимую для создания класса? Как сгенерированные методы интерфейса могут быть вызваны на конкретном экземпляре? Это класс, который генерируется только в памяти?

Я счастлив, что это работает, но это не очень приятно. Возможность Magentos использовать атрибуты, созданные автоматически расширениями, является одним из ключевых факторов его успеха. Как разработчик модулей, я считаю, что мне нужно глубокое понимание всего процесса.
Если бы у меня было время, я бы сам покопался в этом, но я бы предпочел, если бы я мог получить объяснение.

ОБНОВЛЕНИЕ 2 : Потребовалось немного времени, чтобы прочитать \Magento\Framework\Api\Code\Generator\ExtensionAttributesInterfaceGeneratorи \Magento\Framework\Api\Code\Generator\ExtensionAttributesGenerator. Теперь, по крайней мере, у меня есть приблизительное представление о том, что происходит. Если никто не побьет меня, я напишу описание всего процесса в один момент, так как я думаю, что это будет полезной ссылкой.


2
сделал The Vinai .. задал вопрос .. OMG
Амит Бера

Ответы:


26

Прежде всего автогенерация происходит на основе суффикса имени класса, например Factory, ExtensionInterface(см. \Magento\Framework\Api\Code\Generator\ExtensionAttributesInterfaceGenerator::EXTENSION_INTERFACE_SUFFIX) Или Extension(см. \Magento\Framework\Api\Code\Generator\ExtensionAttributesGenerator::EXTENSION_SUFFIX).

Правильный генератор выбирается на основе суффикса здесь \Magento\Framework\Code\Generator::generateClass.

Давайте предположим, что режим Magento активирован, developerа недостающие классы могут быть сгенерированы на лету (аналогичный процесс будет происходить при использовании компилятора). Когда менеджер объектов пытается создать экземпляр, скажем, Magento\Quote\Api\Data\CartItemExtensionFactoryи он не существует, происходит следующее:

  1. Автозагрузчик не может создать экземпляр класса и инициирует генерацию кода здесь \Magento\Framework\Code\Generator\Autoloader::load
  2. Тогда суффикс класса определяется как Factory(список всех объявленных суффиксов можно найти здесь \Magento\Framework\ObjectManager\DefinitionFactory::getCodeGenerator) и соответствующий класс генератора Factory ( Magento\Framework\ObjectManager\Code\Generator\Factory) используется для генерации отсутствующей фабрики
  3. Все автоматически сгенерированные классы всегда основаны на других классах, в случае фабрики, имя исходного класса вычисляется только путем удаления Factoryсуффикса, так и будет Magento\Quote\Api\Data\CartItemExtension. Этот класс не существует и автогенерация снова запускается автозагрузчиком, но на этот раз для класса Extension
  4. Теперь суффикс есть Extensionи \Magento\Framework\Api\Code\Generator\ExtensionAttributesGeneratorбудет использоваться для генерации этого класса
  5. Исходный класс для генерации класса расширения рассчитывается так Magento\Quote\Api\Data\CartItemInterface, как он существует, и класс расширения успешно генерируется. Тем не менее, при попытке включить файл класса расширений автогенерация запускается еще раз, потому что Magento\Quote\Api\Data\CartItemExtensionреализует Magento\Quote\Api\Data\CartItemExtensionInterface, который не существует
  6. Суффикс есть ExtensionInterfaceи \Magento\Framework\Api\Code\Generator\ExtensionAttributesInterfaceGeneratorбудет использоваться для генерации
  7. Классы ExtensionInterface и Extension генерируются на основе информации extension_attributes.xml, доступной через \Magento\Framework\Api\ExtensionAttribute\Config, затем генерируется Factory.

Важным примечанием является то, что в ExtensionInterface нет предпочтений, di.xmlтак как Extension и ExtensionInterface генерируются автоматически. Это не проблема, потому что ExtentionInterface не предполагается вводить напрямую через конструкцию.


@ Винай, пожалуйста. Баунти был приятным сюрпризом, спасибо. Обновление: только к вашему сведению, если награда была начата после того, как ответ был принят, она не присуждается автоматически.
Алекс Палиаруш

0

Для меня сегодня вечером, в верхней части ответа от @Alex, я вижу строки

$modelReflection = new \ReflectionClass($extensibleClassName);
        if ($modelReflection->isInterface()
            && $modelReflection->isSubclassOf(self::EXTENSIBLE_INTERFACE_NAME)
            && $modelReflection->hasMethod('getExtensionAttributes')
        ) {
            $this->classInterfaceMap[$extensibleClassName] = $extensibleClassName;
            return $this->classInterfaceMap[$extensibleClassName];
        }

в классе \Magento\Framework\Api\ExtensionAttributesFactory

мы можем начать отладку, если интерфейс расширения не генерируется. В значительной степени атрибуты расширения предназначены для структурирования нашего класса, как и ожидал Magento 2.

эти строки говорят:

  • это класс в нашем extension_attributes интерфейс

  • это расширяет \ Magento \ Framework \ Api \ ExtensibleDataInterface

  • имеет этот интерфейс функцию с именем getExtensionAttributes

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.