¿Por qué algunas clases definen inyecciones tanto en su constructor como en di.xml?

12

No entiendo por qué, en algunas clases, sus inyecciones de dependencia se declaran dos veces, una en di.xmly en el constructor de la clase concreta.

Por ejemplo Magento\Backend\Model\Url, di.xmltiene definido este conjunto de tipos para DI:

<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>

Pero al mismo tiempo, en su clase concreta, las clases definidas en di.xml requeridas para inyección se vuelven a declarar nuevamente en el constructor:

<?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 = []
) {
    //...
}
?>

Si miramos su constructor arriba \Magento\Framework\App\Route\ConfigInterface $routeConfig, por ejemplo, no está definido en di.xml. Solo se define en el constructor y Magento todavía inyectará routeConfigen la clase para su uso, ¿no? Lo mismo para \Magento\Framework\Encryption\EncryptorInterface $encryptory algunos otros.

Entonces, ¿por qué existe la necesidad de definir las otras inyecciones en ambos di.xmly en el constructor cuando tener esas declaraciones en el constructor es suficiente para que Magento inyecte esas dependencias en la clase para su uso?

xenón
fuente

Respuestas:

15

Como se indica en la documentación , en Magento 2, di.xmlse puede utilizar para hacer lo siguiente:

Puede configurar los argumentos del constructor de clases en su di.xmlnodo de argumento. El administrador de objetos inyecta estos argumentos en la clase durante la creación. El nombre del argumento configurado en el archivo XML debe corresponder al nombre del parámetro en el constructor en la clase configurada.

En su caso es un poco complejo. Voy a explicar cada argumento uno por uno:

  • \Magento\Framework\App\Route\ConfigInterface $routeConfig: esta es una interfaz, por lo que no se puede usar directamente . La preferencia para esta clase se define enapp/etc/di.xml y es la Magento\Framework\App\Route\Configclase
  • \Magento\Framework\App\RequestInterface $request : lo mismo ocurre con esta clase, la preferencia es Magento\Framework\App\Request\Http
  • \Magento\Framework\Url\SecurityInfoInterface $urlSecurityInfo: el mismo caso aquí nuevamente con Magento\Framework\Url\SecurityInfo\Proxyla preferencia
  • \Magento\Framework\Url\ScopeResolverInterface $scopeResolver: aquí comenzamos con lo interesante. En app/etc/di.xmluna preferencia se define para esta interfaz y es la Magento\Framework\Url\ScopeResolverclase. Sin embargo, para el Magento\Backend\Model\UrlMagento 2 necesita usar otra clase y, por lo tanto, define qué clase en el di.xmlque publicó Magento\Backend\Model\Url\ScopeResolverse usará.
  • \Magento\Framework\Session\Generic $session Esta es una clase normal y, por lo tanto, se puede utilizar como tal.
  • \Magento\Framework\Session\SidResolverInterface $sidResolver: volver a una interfaz, la preferencia aún está definida app/etc/di.xmly esMagento\Framework\Session\SidResolver\Proxy
  • \Magento\Framework\Url\RouteParamsResolverFactory $routeParamsResolverFactory : esta es una clase de fábrica, por lo que puede usarse como tal.
  • \Magento\Framework\Url\QueryParamsResolverInterface $queryParamsResolver: volver a nuestro app/etc/di.xmly la preferencia esMagento\Framework\Url\QueryParamsResolver
  • \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig: otro caso aquí donde ** se define una preferencia app/etc/di.xmly lo es Magento\Framework\App\Config.
  • $scopeType: aquí solo tenemos una variable sin ninguna clase en frente. Su módulo di.xmlespecifica que Magento\Store\Model\ScopeInterface::SCOPE_STOREdebe usarse como el valor de esta variable. **
  • \Magento\Backend\Helper\Data $backendHelper: aquí podríamos usar esa clase como tal. Sin embargo, aquí se usa un proxy porque esta clase no se usa necesariamente (consulte esta publicación para obtener detalles sobre las clases de proxy: Magento 2: ¿explicación práctica de qué es una clase de proxy? )
  • \Magento\Backend\Model\Menu\Config $menuConfig : podemos usar esta clase como tal.
  • \Magento\Framework\App\CacheInterface $cache: otra preferencia definida en app/etc/di.xmlesta interfaz que esMagento\Framework\App\Cache\Proxy
  • \Magento\Backend\Model\Auth\Session $authSession: lo mismo aquí, podríamos haber usado la clase, pero en su lugar usamos una clase proxy para la carga diferida.
  • \Magento\Framework\Encryption\EncryptorInterface $encryptor: saltando a la app/etc/di.xmlotra vez y encontramos Magento\Framework\Encryption\Encryptorcomo preferencia
  • \Magento\Store\Model\StoreFactory $storeFactory : una fábrica para que podamos usarlo como tal.
  • \Magento\Framework\Data\Form\FormKey $formKey: aquí usamos Magento\Framework\Data\Form\FormKey\Proxynuevamente la clase proxy para la carga diferida.
  • array $data = []: este siempre es el último y se establece automáticamente en una matriz vacía. Puede encontrar más información aquí: Magento 2: ¿cuál es el parámetro del constructor de matriz de datos $?

Para resumir

Globalmente, los parámetros de los constructores de clases son interfaces o clases no instanciables. Por lo tanto, le di.xmlpermite personalizar las dependencias que desea utilizar para cada constructor de clases. También es válido para clases instanciables. Por ejemplo, un constructor de clase que toma una clase de producto como argumento de constructor. Se puede adaptar en el módulo de producto configurable para que tome una clase de producto configurable como argumento.

Raphael en Digital Pianism
fuente
¿Se requiere siempre una preferencia para un parámetro de interfaz? ¿Se puede ver como una alternativa? ¿Tiene sentido simplemente definir un argumento concreto en la configuración sin tener preferencia en ningún lado? ¿O eso no es posible?
robsch
6

Es importante comprender la diferencia entre la definición de dependencias y la configuración de dependencias.

Las dependencias no están definidas dentro de di.xml. Las dependencias se definen dentro del constructor de la clase respectiva especificando una interfaz, un resumen o una fábrica como el tipo de esa dependencia específica, por ejemplo, $routeConfiges una dependencia de tipo \Magento\Framework\App\Route\ConfigInterface.

Por otro lado, di.xmles el lugar para configurar las dependencias mediante el uso de <preference/>nodos y / o xpath:type/arguments/argumentnodos (a veces junto con nodos de configuración más avanzados como <virtualType/>o <proxy/>). Configurar una dependencia simplemente significa mapear el argumento constructor de un objeto a una implementación / objeto / concreto .

Desea que las dependencias sean configurables a través de di.xml para poder intercambiarlas y usar una implementación diferente para una determinada interfaz o argumento bajo ciertas condiciones (siga leyendo el ejemplo para comprender qué se supone que significan ciertas condiciones).

Por ejemplo, al desarrollar su extensión, primero debe crear una nueva clase (llamamos a esta nueva clase una implementación ). Su nueva clase implementa la \Magento\Framework\App\Route\ConfigInterfaceinterfaz y tiene dentro de su cuerpo una funcionalidad concreta que hace honor al contrato de la interfaz. Ahora comienza la parte de configuración : para decirle a Magento que use su implementación recién definida, debe configurar esta implementación como una dependencia para el objeto Magento\Backend\Model\Url . Realiza esta configuración dentro de los di.xmlarchivos o su módulo. En este caso, debe usar el <preference/>nodo para asignar la interfaz a su nueva implementación. Otras veces usaría el xpath:type/arguments/argument di.xmlnodo más granular paramapear solo argumentos específicos (también conocidos como dependencias, también conocidos como interfaces) de implementaciones concretas a específicas . Ahora, su aplicación sólo estará activa como una dependencia para el objeto \Magento\Backend\Model\Url en ciertas condiciones , por ejemplo, en el flujo de la ejecución de código de la solicitud de aplicación actual un objeto del tipo Magento\Backend\Model\Urlque se está creando y que necesita una aplicación para el definido constructor de la dependencia llamada $routeConfigque es de tipo \Magento\Framework\App\Route\ConfigInterface.

Es más o menos como decir:

"¡Hola, Sr. ObjectManager! Siempre que Magento\Backend\Model\Urlse solicite una instancia de tipo de objeto, primero eche un vistazo a su definición de constructor de clase y analice las dependencias definidas en ella. Quiero que luego busque dentro de di.xmlla configuración HTTP final combinada de la solicitud HTTP actual. para cada dependencia configurada que se define en el constructor de clase Magento \ Backend \ Model \ Url . Usted me da esa implementación de dependencia configurada ".

adjco
fuente