W jaki sposób Magento2 generuje określone ExtensionFactory i ExtensionAttributeInterface?

28

Chciałbym owinąć głowę przy użyciu atrybutów rozszerzenia, na przykład w przypadku cytatów.
Nie ma problemu z dodaniem niestandardowego atrybutu do takiej encji przy użyciu klasy konfiguracji jak w Magento 1, nie o to chodzi w tym pytaniu.
W tej chwili magia mnie przytłacza, gdy chcę ujawnić taki atrybut, który został dodany przez rozszerzenie poprzez interfejs API jednostek jako atrybut rozszerzenia.

AKTUALIZACJA : Wiem, jak powstają zwykłe fabryki. To pytanie dotyczy specjalnych fabryk, które tworzą instancje wygenerowanych implementacji dla wygenerowanych interfejsów atrybutów rozszerzenia.

Oto kroki, które podejmuję, aby to działało. Dodam je, aby ktokolwiek próbował odpowiedzieć, nie musiał wchodzić w te szczegóły.
Moje pytanie brzmi: JAK lub DLACZEGO działa.

Kroki ujawniania atrybutu rozszerzenia za pośrednictwem interfejsu API encji:

  1. Utwórz, etc/extension_attributes.xmlktóry dodaje atrybut do interfejsu encji
  2. Utwórz wtyczkę, aby dodać wartość atrybutu do ExtensionAttributesinstancji encji .

Aby wykonać drugi punkt, ExtensionAttributespotrzebna jest instancja encji . Z tego powodu wtyczka zależy od fabryki, którą menedżer obiektów dostarcza przez DI.

Do wyceny Magento\Quote\Api\Data\CartItemExtensionFactorynależy użyć przykładu.
Myślę, że rodzaj tej fabryki musi w jakiś sposób wyzwalać magię generacji.

Magento następnie generuje pasujący interfejs \Magento\Quote\Api\Data\CartItemExtensionInterfacez ustawiającymi i pobierającymi dla wszystkich atrybutów rozszerzenia.
Wydaje się jednak, że nie generuje konkretnej implementacji tego interfejsu. Przynajmniej PHPStorm tego nie widzi.

W jaki sposób Magento gromadzi informacje potrzebne do wygenerowania klasy? Jak można wywoływać wygenerowane metody interfejsu w konkretnej instancji? Czy jest to klasa generowana tylko w pamięci?

Cieszę się, że to działa, ale to nie jest naprawdę satysfakcjonujące. Zdolność Magentos do używania atrybutów tworzonych automatycznie przez rozszerzenia jest jednym z kluczowych czynników sukcesu. Jako programista modułów uważam, że potrzebuję dokładnego zrozumienia całego procesu.
Gdybym miał czas, po prostu zagłębiłbym się w to sam, ale wolałbym, gdybym tylko mógł uzyskać wyjaśnienie.

AKTUALIZACJA 2 : Trochę czasu zajęło mi przeczytanie \Magento\Framework\Api\Code\Generator\ExtensionAttributesInterfaceGeneratori \Magento\Framework\Api\Code\Generator\ExtensionAttributesGenerator. Teraz mam przynajmniej ogólne pojęcie o tym, co się dzieje. Jeśli nikt mnie nie pobije, napiszę opis pełnego procesu w pewnym momencie, ponieważ uważam, że byłoby to przydatne odniesienie.

Vinai
źródło
2
zrobił Vinai .. zadał pytanie ..Omg
Amit Bera

Odpowiedzi:

26

Przede wszystkim autogeneration dzieje się na podstawie nazwy klasy przyrostka, np Factory, ExtensionInterface(patrz \Magento\Framework\Api\Code\Generator\ExtensionAttributesInterfaceGenerator::EXTENSION_INTERFACE_SUFFIX) lub Extension(zobacz \Magento\Framework\Api\Code\Generator\ExtensionAttributesGenerator::EXTENSION_SUFFIX).

Właściwy generator jest wybierany na podstawie sufiksu tutaj \Magento\Framework\Code\Generator::generateClass.

Załóżmy, że tryb Magento jest developeri brakujące klasy mogą być generowane w locie (podobny proces nastąpi, gdy zostanie użyty kompilator). Gdy menedżer obiektów próbuje utworzyć instancję, powiedzmy, Magento\Quote\Api\Data\CartItemExtensionFactoryi nie istnieje, następują:

  1. Autoloader nie tworzy instancji klasy i inicjuje tutaj generowanie kodu \Magento\Framework\Code\Generator\Autoloader::load
  2. Następnie określany jest przyrostek klasy jako Factory(lista wszystkich zadeklarowanych przyrostków znajduje się tutaj \Magento\Framework\ObjectManager\DefinitionFactory::getCodeGenerator) i odpowiednia klasa generatora fabryki ( Magento\Framework\ObjectManager\Code\Generator\Factory) służy do generowania brakującej fabryki
  3. Wszystkie automatycznie generowane klasy są zawsze oparte na innych klasach, w przypadku fabryki nazwa klasy źródłowej jest obliczana przez usunięcie Factorysufiksu, tak będzie Magento\Quote\Api\Data\CartItemExtension. Ta klasa nie istnieje i autogeneracja jest ponownie wywoływana przez autoloader, ale tym razem dla klasy Extension
  4. Teraz przyrostek jest Extensioni \Magento\Framework\Api\Code\Generator\ExtensionAttributesGeneratorbędzie używany do generowania tej klasy
  5. Klasa źródłowa do generowania klasy rozszerzenia jest obliczana jako Magento\Quote\Api\Data\CartItemInterface, ponieważ istnieje i klasa rozszerzenia została pomyślnie wygenerowana. Jednak przy próbie dołączenia pliku klasy rozszerzenia automatyczne generowanie jest ponownie uruchamiane, ponieważ Magento\Quote\Api\Data\CartItemExtensionimplementuje Magento\Quote\Api\Data\CartItemExtensionInterface, który nie istnieje
  6. Przyrostek jest ExtensionInterfacei \Magento\Framework\Api\Code\Generator\ExtensionAttributesInterfaceGeneratorbędzie używany do generowania
  7. Klasy ExtensionInterface i Extension są generowane na podstawie informacji extension_attributes.xml, dostępnych za pośrednictwem \Magento\Framework\Api\ExtensionAttribute\Config, a następnie generowane jest Factory

Jedna ważna uwaga jest taka, że ​​nie ma preferencji dla ExtensionInterface, di.xmlponieważ zarówno Extension, jak i ExtensionInterface są generowane automatycznie. Nie stanowi to problemu, ponieważ interfejs ExtentionInterface nie powinien być wstrzykiwany bezpośrednio przez konstrukt.

Alex Paliarush
źródło
@Vinai nie ma za co. Dzięki Bounty była miłą niespodzianką. Aktualizacja: tylko FYI, jeśli nagroda została rozpoczęta po zaakceptowaniu odpowiedzi, nie jest przyznawana automatycznie.
Alex Paliarush,
0

Dla mnie dziś wieczorem, poza odpowiedzią z @Alex, widzę linie

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

w klasie \Magento\Framework\Api\ExtensionAttributesFactory

tam, gdzie możemy chcieć rozpocząć debugowanie, jeśli interfejs rozszerzenia nie jest generowany. Prawie atrybuty rozszerzenia dotyczą strukturyzacji naszej klasy, tak jak tego oczekuje Magento 2.

te linie mówią:

  • to klasa w naszym rozszerzeniu atrybuty interfejsu

  • czy rozszerza \ Magento \ Framework \ Api \ ExtensibleDataInterface

  • ma ten interfejs funkcję o nazwie getExtensionAttributes

Herve Tribouilloy
źródło