Como o Magento2 gera os ExtensionFactory e ExtensionAttributeInterface específicos?

28

Eu gostaria de entender os atributos de extensão, por exemplo, para itens de cotação.
Não há problema em adicionar um atributo personalizado a uma entidade usando uma classe de instalação como no Magento 1, não é sobre isso que se trata.
No momento, a mágica me impressiona quando quero expor um atributo que foi adicionado por uma extensão por meio da API de entidades como um atributo de extensão.

ATUALIZAÇÃO : Eu sei como as fábricas regulares são geradas. Esta pergunta é sobre as fábricas especiais que instanciam as implementações geradas para as interfaces de atributo de extensão geradas.

Aqui estão os passos que eu tomo para fazê-lo funcionar. Estou adicionando esses itens para que quem tente responder não precise entrar nesses detalhes.
A minha pergunta é COMO ou POR QUE funciona.

Etapas para expor um atributo de extensão por meio de uma API da entidade:

  1. Crie um etc/extension_attributes.xmlque adicione o atributo à interface da entidade
  2. Crie um plug-in para adicionar o valor do atributo à ExtensionAttributesinstância de entidades .

Para fazer o segundo ponto, a ExtensionAttributesinstância de entidades é necessária. Por esse motivo, o plug-in depende de uma fábrica, que o gerenciador de objetos fornece via DI.

Para o item de cotação, o exemplo Magento\Quote\Api\Data\CartItemExtensionFactorydeve ser usado.
Eu acho que o tipo dessa fábrica de alguma forma deve ser o gatilho para a geração mágica.

O Magento gera a interface correspondente \Magento\Quote\Api\Data\CartItemExtensionInterfacecom os setters e getters para todos os atributos de extensão.
No entanto, parece não gerar a implementação concreta para essa interface. No momento, o PHPStorm não está vendo.

Como o Magento coleta as informações necessárias para gerar a classe? Como os métodos de interface gerados podem ser chamados em uma instância concreta? É uma classe que é gerada apenas na memória?

Estou feliz que funcione, mas isso não é realmente satisfatório. A capacidade do Magentos de usar atributos criados automaticamente por extensões é um fator chave para seu sucesso. Como desenvolvedor de módulos, acredito que preciso de um entendimento completo de todo o processo.
Se eu tivesse tempo, eu mesmo iria me aprofundar nisso, mas preferiria se pudesse obter uma explicação.

ATUALIZAÇÃO 2 : Demorou um pouco para ler \Magento\Framework\Api\Code\Generator\ExtensionAttributesInterfaceGeneratore ler \Magento\Framework\Api\Code\Generator\ExtensionAttributesGenerator. Agora, pelo menos, tenho uma ideia aproximada do que está acontecendo. Se ninguém me bater, escreverei uma descrição do processo completo em um ponto, pois acho que seria uma referência útil.

Vinai
fonte
2
fez o The Vinai .. fez a pergunta .. Omg
Amit Bera

Respostas:

26

Antes de tudo, a geração automática está acontecendo com base no sufixo do nome da classe, por exemplo Factory, ExtensionInterface(consulte \Magento\Framework\Api\Code\Generator\ExtensionAttributesInterfaceGenerator::EXTENSION_INTERFACE_SUFFIX) ou Extension(consulte \Magento\Framework\Api\Code\Generator\ExtensionAttributesGenerator::EXTENSION_SUFFIX).

O gerador apropriado é selecionado com base no sufixo aqui \Magento\Framework\Code\Generator::generateClass.

Vamos assumir que o modo Magento está developere as classes ausentes podem ser geradas em tempo real (processos semelhantes acontecerão quando o compilador for usado). Quando o gerenciador de objetos tenta instanciar, digamos, Magento\Quote\Api\Data\CartItemExtensionFactorye ele não existe, acontece o seguinte:

  1. O carregador automático falha ao instanciar a classe e inicia a geração de código aqui \Magento\Framework\Code\Generator\Autoloader::load
  2. O sufixo da classe é determinado como Factory(a lista de todos os sufixos declarados pode ser encontrada aqui \Magento\Framework\ObjectManager\DefinitionFactory::getCodeGenerator) e a classe do gerador de Fábrica correspondente ( Magento\Framework\ObjectManager\Code\Generator\Factory) é usada para gerar a falta de fábrica
  3. Todas as classes geradas automaticamente são sempre baseadas em outras classes; no caso de fábrica, o nome da classe de origem é calculado apenas com a remoção do Factorysufixo Magento\Quote\Api\Data\CartItemExtension. Essa classe não existe e a geração automática é invocada mais uma vez pelo carregador automático, mas desta vez para a classe Extension
  4. Agora o sufixo é Extensione \Magento\Framework\Api\Code\Generator\ExtensionAttributesGeneratorserá usado para gerar esta classe
  5. A classe de origem para a geração da classe de extensão é calculada como Magento\Quote\Api\Data\CartItemInterfaceexiste e a classe de extensão é gerada com êxito. No entanto, na tentativa de incluir o arquivo da classe Extension, a geração automática é acionada mais uma vez porque Magento\Quote\Api\Data\CartItemExtensionimplementa Magento\Quote\Api\Data\CartItemExtensionInterface, o que não existe
  6. O sufixo é ExtensionInterfacee \Magento\Framework\Api\Code\Generator\ExtensionAttributesInterfaceGeneratorserá usado para geração
  7. As classes ExtensionInterface e Extension são geradas com base em informações de extension_attributes.xml, acessíveis via e \Magento\Framework\Api\ExtensionAttribute\Config, em seguida, o Factory é gerado

Uma observação importante é que não há preferência pelo ExtensionInterface di.xmlporque o Extension e o ExtensionInterface são gerados automaticamente. Isso não é um problema porque não se espera que ExtentionInterface seja injetado diretamente através da construção.

Alex Paliarush
fonte
@Vinai, de nada. Bounty foi uma boa surpresa, obrigado. Atualização: apenas para sua informação, se a recompensa foi iniciada após a resposta ter sido aceita, ela não é concedida automaticamente.
Alex Paliarush
0

Para mim, hoje à noite, além da resposta de @Alex, posso ver as linhas

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

na aula \Magento\Framework\Api\ExtensionAttributesFactory

é onde podemos começar a depurar se a interface de extensão não estiver sendo gerada. Praticamente os atributos de extensão são sobre a estruturação de nossa classe, como o Magento 2 espera.

estas linhas estão dizendo:

  • é a classe em nossa extension_attributes uma interface

  • estende \ Magento \ Framework \ Api \ ExtensibleDataInterface

  • possui nessa interface uma função chamada getExtensionAttributes

Herve Tribouilloy
fonte