Por que algumas classes definem injeções no construtor e no di.xml?

12

Não entendo por que, em algumas classes, suas injeções de dependência são declaradas duas vezes - uma vez no di.xmlconstrutor da classe concreta e no.

Por exemplo Magento\Backend\Model\Url, em , di.xmltem este conjunto de tipos para DI definido:

<type name="Magento\Backend\Model\Url">
    <arguments>
        <argument name="scopeResolver" xsi:type="object">
Magento\Backend\Model\Url\ScopeResolver</argument>
        <argument name="authSession" xsi:type="object">
Magento\Backend\Model\Auth\Session\Proxy</argument>
        <argument name="formKey" xsi:type="object">
Magento\Framework\Data\Form\FormKey\Proxy</argument>
        <argument name="scopeType" xsi:type="const">
Magento\Store\Model\ScopeInterface::SCOPE_STORE </argument>
        <argument name="backendHelper" xsi:type="object">
Magento\Backend\Helper\Data\Proxy</argument>
    </arguments>
</type>

Mas, ao mesmo tempo, em sua classe concreta, as classes definidas em di.xml necessárias para injeção são declaradas novamente no construtor:

<?php
    public function __construct(
        \Magento\Framework\App\Route\ConfigInterface $routeConfig,
        \Magento\Framework\App\RequestInterface $request,
        \Magento\Framework\Url\SecurityInfoInterface $urlSecurityInfo,
        \Magento\Framework\Url\ScopeResolverInterface $scopeResolver,
        \Magento\Framework\Session\Generic $session,
        \Magento\Framework\Session\SidResolverInterface $sidResolver,
        \Magento\Framework\Url\RouteParamsResolverFactory $routeParamsResolverFactory,
        \Magento\Framework\Url\QueryParamsResolverInterface $queryParamsResolver,
        \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
        $scopeType,
        \Magento\Backend\Helper\Data $backendHelper,
        \Magento\Backend\Model\Menu\Config $menuConfig,
        \Magento\Framework\App\CacheInterface $cache,
        \Magento\Backend\Model\Auth\Session $authSession,
        \Magento\Framework\Encryption\EncryptorInterface $encryptor,
        \Magento\Store\Model\StoreFactory $storeFactory,
        \Magento\Framework\Data\Form\FormKey $formKey,
        array $data = []
) {
    //...
}
?>

Se olharmos para o construtor acima \Magento\Framework\App\Route\ConfigInterface $routeConfig, por exemplo, não está definido em di.xml. Ele é definido apenas no construtor e o Magento ainda injeta o conteúdo routeConfigna classe para uso, não é? Mesmo para \Magento\Framework\Encryption\EncryptorInterface $encryptore alguns outros.

Então, por que há uma necessidade de definir as outras injeções nos di.xmlconstrutores e no construtor quando ter essas declarações no construtor é suficiente para o Magento injetar essas dependências na classe para uso?

xenon
fonte

Respostas:

15

Conforme declarado na documentação , no Magento 2, o di.xmlpode ser usado para fazer o seguinte:

Você pode configurar os argumentos do construtor de classe no seu di.xmlno nó do argumento. O gerenciador de objetos injeta esses argumentos na classe durante a criação. O nome do argumento configurado no arquivo XML deve corresponder ao nome do parâmetro no construtor na classe configurada.

No seu caso, é um pouco complexo. Vou explicar cada argumento um por um:

  • \Magento\Framework\App\Route\ConfigInterface $routeConfig: esta é uma interface, portanto não pode ser usada diretamente . A preferência por esta classe é definidaapp/etc/di.xml e é a Magento\Framework\App\Route\Configclasse
  • \Magento\Framework\App\RequestInterface $request : o mesmo vale para esta classe, a preferência é Magento\Framework\App\Request\Http
  • \Magento\Framework\Url\SecurityInfoInterface $urlSecurityInfo: mesmo caso aqui novamente com Magento\Framework\Url\SecurityInfo\Proxycomo a preferência
  • \Magento\Framework\Url\ScopeResolverInterface $scopeResolver: aqui começamos com a parte interessante. Em app/etc/di.xmluma preferência é definida para essa interface e é a Magento\Framework\Url\ScopeResolverclasse. No entanto, o Magento\Backend\Model\UrlMagento 2 precisa usar outra classe e, portanto, define qual classe no di.xmlpost que você postou Magento\Backend\Model\Url\ScopeResolverserá usada.
  • \Magento\Framework\Session\Generic $session esta é uma classe normal e, portanto, pode ser usada como ela.
  • \Magento\Framework\Session\SidResolverInterface $sidResolver: de volta a uma interface, a preferência ainda é definida app/etc/di.xmle éMagento\Framework\Session\SidResolver\Proxy
  • \Magento\Framework\Url\RouteParamsResolverFactory $routeParamsResolverFactory : esta é uma classe de fábrica para que possa ser usada como ela.
  • \Magento\Framework\Url\QueryParamsResolverInterface $queryParamsResolver: de volta ao nosso app/etc/di.xmle a preferência éMagento\Framework\Url\QueryParamsResolver
  • \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig: outro caso aqui em que ** uma preferência é definida app/etc/di.xmle é Magento\Framework\App\Config.
  • $scopeType: aqui só temos uma variável sem nenhuma classe à sua frente. Seu módulo di.xmlespecifica que Magento\Store\Model\ScopeInterface::SCOPE_STOREdeve ser usado como o valor dessa variável. **
  • \Magento\Backend\Helper\Data $backendHelper: aqui poderíamos usar essa classe como ela. No entanto, aqui um proxy é usado porque esta classe não está sendo necessariamente usada (consulte este post para obter detalhes sobre classes de proxy: Magento 2: explicação prática do que é uma classe de proxy? )
  • \Magento\Backend\Model\Menu\Config $menuConfig : podemos usar essa classe como ela.
  • \Magento\Framework\App\CacheInterface $cache: outra preferência definida app/etc/di.xmlpara essa interface que éMagento\Framework\App\Cache\Proxy
  • \Magento\Backend\Model\Auth\Session $authSession: mesmo aqui novamente, poderíamos ter usado a classe como ela, mas usamos uma classe proxy em vez disso para carregamento lento.
  • \Magento\Framework\Encryption\EncryptorInterface $encryptor: saltando para o app/etc/di.xmlnovo e encontramos Magento\Framework\Encryption\Encryptorcomo preferência
  • \Magento\Store\Model\StoreFactory $storeFactory : uma fábrica para que possamos usá-lo como ele.
  • \Magento\Framework\Data\Form\FormKey $formKey: aqui usamos uma Magento\Framework\Data\Form\FormKey\Proxyclasse proxy novamente para carregamento lento.
  • array $data = []: este sempre vem por último e é automaticamente padronizado para um array vazio. Você pode encontrar mais informações aqui: Magento 2: qual é o parâmetro do construtor $ data array?

Resumir

Globalmente, os parâmetros de construtores de classes são interfaces ou classes não instanciadas. Assim, di.xmlvocê pode personalizar as dependências que deseja usar para cada construtor de classe. Também é válido para classes instantâneas. Por exemplo, um construtor de classe que usa uma classe de produto como argumento do construtor. Ele pode ser adaptado no módulo de produto configurável, de modo que seja usada como uma classe de produto configurável.

Raphael na Digital Pianism
fonte
Sempre é necessária uma preferência para um parâmetro de interface? Pode ser visto como um substituto? Faz sentido definir apenas um argumento concreto na configuração sem ter uma preferência em lugar algum? ou isso não é possível?
robsch 27/05/19
6

É importante entender a diferença entre definição de dependências e configuração de dependências.

As dependências não são definidas no di.xml. As dependências são definidas dentro do construtor da respectiva classe, especificando uma interface, um resumo ou uma fábrica como o tipo dessa dependência específica, por exemplo, $routeConfigé uma dependência do tipo \Magento\Framework\App\Route\ConfigInterface.

Por outro lado, di.xmlé o local para configurar as dependências usando <preference/>nós e / ou xpath:type/arguments/argumentnós (às vezes combinados com nós de configuração mais avançados, como <virtualType/>ou <proxy/>). Configurar uma dependência significa simplesmente mapear o argumento construtor de um objeto para uma implementação / objeto / concreto .

Você deseja que as dependências sejam configuráveis ​​via di.xml, para poder trocá-las e usar uma implementação diferente para uma determinada interface ou argumento sob certas condições (continue lendo o exemplo para entender o que determinadas condições devem significar).

Por exemplo, ao desenvolver sua extensão, você primeiro criaria uma nova classe (chamamos essa nova classe de implementação ). Sua nova classe implementa a \Magento\Framework\App\Route\ConfigInterfaceinterface e possui em seu corpo uma funcionalidade concreta que respeita o contrato da interface. Agora começa a parte da configuração : para dizer ao Magento para usar sua implementação recém-definida, você deve configurá-la como uma dependência para o objeto Magento\Backend\Model\Url . Você faz essa configuração dentro dos di.xmlarquivos ou do seu módulo. Nesse caso, você precisa usar o <preference/>nó para mapear a interface para sua nova implementação. Outras vezes, você usaria o xpath:type/arguments/argument di.xmlnó mais granular paramapeie apenas argumentos específicos (também conhecidos como dependências, também conhecidos como interfaces) de um concreto para implementações específicas . Agora, sua implementação estará ativa apenas como uma dependência para o objeto \Magento\Backend\Model\Url em determinadas condições , por exemplo, no fluxo de execução de código da solicitação de aplicativo atual, um objeto do tipo Magento\Backend\Model\Urlestá sendo criado e precisa de uma implementação para a dependência definida pelo construtor chamada $routeConfigqual é de tipo \Magento\Framework\App\Route\ConfigInterface.

É como dizer:

"Ei, Sr. ObjectManager! Sempre que uma instância de objeto do tipo Magento\Backend\Model\Urlfor solicitada, verifique primeiro a definição do construtor de classe e analise as dependências definidas nela. Quero que você procure dentro da final, mesclada di.xmlda solicitação HTTP atual, a configuração para cada dependência configurado que está definido no construtor da classe Magento \ backend \ Modelo \ Url . Você me dá que configurado implementação dependência ".

adjco
fonte