Pourquoi certaines classes définissent les injections à la fois dans leur constructeur et dans di.xml?

12

Je ne comprends pas pourquoi, dans certaines classes, leurs injections de dépendances sont déclarées deux fois - une fois dans le di.xmlconstructeur de la classe concrète.

Par exemple dans Magento\Backend\Model\Url, son di.xmla cet ensemble de types pour DI défini:

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

Mais en même temps, dans sa classe concrète, les classes définies dans di.xml requises pour l'injection sont à nouveau déclarées dans le constructeur:

<?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 nous regardons son constructeur ci-dessus \Magento\Framework\App\Route\ConfigInterface $routeConfig, par exemple, il n'est pas défini dans di.xml. Il n'est défini que dans le constructeur et Magento injectera toujours le routeConfigdans la classe pour utilisation, n'est-ce pas? Pareil pour \Magento\Framework\Encryption\EncryptorInterface $encryptoret quelques autres.

Alors, pourquoi est-il nécessaire de définir les autres injections à la fois di.xmlet dans le constructeur quand avoir ces déclarations dans le constructeur est suffisant pour que Magento injecte ces dépendances dans la classe pour utilisation?

xénon
la source

Réponses:

15

Comme indiqué dans la documentation , dans Magento 2, le di.xmlpeut être utilisé pour effectuer les opérations suivantes:

Vous pouvez configurer les arguments du constructeur de classe dans votre di.xmldans le nœud d'argument. Le gestionnaire d'objets injecte ces arguments dans la classe lors de la création. Le nom de l'argument configuré dans le fichier XML doit correspondre au nom du paramètre dans le constructeur de la classe configurée.

Dans votre cas, c'est un peu complexe, je vais expliquer chaque argument un par un:

  • \Magento\Framework\App\Route\ConfigInterface $routeConfig: c'est une interface donc elle n'est pas utilisable directement . La préférence pour cette classe est définie dansapp/etc/di.xml et c'est la Magento\Framework\App\Route\Configclasse
  • \Magento\Framework\App\RequestInterface $request : il en va de même pour cette classe, la préférence est Magento\Framework\App\Request\Http
  • \Magento\Framework\Url\SecurityInfoInterface $urlSecurityInfo: même cas ici encore avec Magento\Framework\Url\SecurityInfo\Proxycomme préférence
  • \Magento\Framework\Url\ScopeResolverInterface $scopeResolver: ici nous commençons par le bit intéressant. Dans app/etc/di.xmlune préférence est définie pour cette interface et c'est la Magento\Framework\Url\ScopeResolverclasse. Cependant, pour que Magento\Backend\Model\UrlMagento 2 doive utiliser une autre classe, il définit donc la classe dans laquelle di.xmlvous avez posté Magento\Backend\Model\Url\ScopeResolverqui sera utilisée.
  • \Magento\Framework\Session\Generic $session il s'agit d'une classe normale et peut donc être utilisée comme telle.
  • \Magento\Framework\Session\SidResolverInterface $sidResolver: retour à une interface, la préférence est toujours définie dans app/etc/di.xmletMagento\Framework\Session\SidResolver\Proxy
  • \Magento\Framework\Url\RouteParamsResolverFactory $routeParamsResolverFactory : il s'agit d'une classe d'usine, il peut donc être utilisé tel quel.
  • \Magento\Framework\Url\QueryParamsResolverInterface $queryParamsResolver: retour à notre app/etc/di.xmlet la préférence estMagento\Framework\Url\QueryParamsResolver
  • \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig: un autre cas ici où ** une préférence est définie dans app/etc/di.xmlet elle l'est Magento\Framework\App\Config.
  • $scopeType: nous n'avons ici qu'une variable sans classe devant elle. Votre module di.xmlspécifie qui Magento\Store\Model\ScopeInterface::SCOPE_STOREdoit être utilisé comme valeur de cette variable. **
  • \Magento\Backend\Helper\Data $backendHelper: ici, nous aurions pu utiliser cette classe comme elle. Cependant, ici, un proxy est utilisé car cette classe n'est pas nécessairement utilisée (voir cet article pour plus de détails sur les classes proxy: Magento 2: explication pratique de ce qu'est une classe proxy? )
  • \Magento\Backend\Model\Menu\Config $menuConfig : nous pouvons utiliser cette classe comme elle.
  • \Magento\Framework\App\CacheInterface $cache: une autre préférence définie dans app/etc/di.xmlpour cette interface qui estMagento\Framework\App\Cache\Proxy
  • \Magento\Backend\Model\Auth\Session $authSession: de même ici nous aurions pu utiliser la classe comme elle mais nous utilisons une classe proxy à la place pour le chargement paresseux.
  • \Magento\Framework\Encryption\EncryptorInterface $encryptor: sauter à app/etc/di.xmlnouveau et on trouve Magento\Framework\Encryption\Encryptorde préférence
  • \Magento\Store\Model\StoreFactory $storeFactory : une usine pour qu'on puisse l'utiliser comme ça.
  • \Magento\Framework\Data\Form\FormKey $formKey: ici, nous utilisons à Magento\Framework\Data\Form\FormKey\Proxynouveau la classe proxy pour le chargement paresseux.
  • array $data = []: celui-ci vient toujours en dernier et est automatiquement défini par défaut sur un tableau vide, vous pouvez trouver plus d'informations ici: Magento 2: quel est le paramètre constructeur du tableau de données $?

Résumer

Globalement, les paramètres des constructeurs de classes sont des interfaces ou des classes non instanciables. di.xmlVous permet ainsi d'adapter les dépendances que vous souhaitez utiliser pour chaque constructeur de classe. Il est également valable pour les classes instanciables. Par exemple, un constructeur de classe qui prend une classe de produit comme argument de constructeur. Il peut être personnalisé dans le module de produit configurable afin qu'il prenne plutôt une classe de produit configurable comme argument.

Raphael chez Digital Pianism
la source
Une préférence est-elle toujours requise pour un paramètre d'interface? Peut-il être considéré comme un repli? Est-il judicieux de simplement définir un argument concret dans la configuration sans avoir de préférence nulle part? Ou n'est-ce pas possible?
robsch
6

Il est important de comprendre la différence entre la définition des dépendances et la configuration des dépendances.

Les dépendances ne sont pas définies dans di.xml. Les dépendances sont définies à l'intérieur du constructeur de la classe respective en spécifiant une interface, un résumé ou une fabrique comme type de cette dépendance spécifique, par exemple $routeConfigune dépendance de type \Magento\Framework\App\Route\ConfigInterface.

D'un autre côté, di.xmlc'est l'endroit pour configurer les dépendances en utilisant des <preference/>nœuds et / ou des xpath:type/arguments/argumentnœuds (parfois couplés à des nœuds de configuration plus avancés comme <virtualType/>ou <proxy/>). Configurer une dépendance signifie simplement mapper l'argument constructeur d'un objet à une implémentation / objet / béton .

Vous voulez que les dépendances soient configurables via di.xml afin que vous puissiez les échanger et utiliser une implémentation différente pour une certaine interface ou un argument sous certaines conditions (continuez à lire l'exemple pour comprendre ce que certaines conditions sont censées signifier).

Par exemple, lorsque vous développez votre extension, vous devez d'abord créer une nouvelle classe (nous appelons cette nouvelle classe une implémentation ). Votre nouvelle classe implémente l' \Magento\Framework\App\Route\ConfigInterfaceinterface et possède à l'intérieur de son corps une fonctionnalité concrète qui respecte le contrat d'interface. Commence maintenant la partie configuration : afin de dire à Magento d'utiliser votre implémentation nouvellement définie, vous devez configurer cette implémentation en tant que dépendance pour l'objet Magento\Backend\Model\Url . Vous effectuez cette configuration à l'intérieur des di.xmlfichiers ou de votre module. Dans ce cas, vous devez utiliser le <preference/>nœud pour mapper l'interface à votre nouvelle implémentation. D'autres fois, vous utiliseriez le xpath:type/arguments/argument di.xmlnœud plus granulaire pourmappez uniquement des arguments spécifiques (aka dépendances, aka interfaces) d'un concret à des implémentations spécifiques . Maintenant, votre implémentation ne sera active que comme dépendance pour l'objet \Magento\Backend\Model\Url dans certaines conditions , par exemple, dans le flux d'exécution de code de la demande d'application actuelle, un objet de type Magento\Backend\Model\Urlest en cours de création et il a besoin d'une implémentation pour la dépendance définie par le constructeur appelée $routeConfigqui est de type \Magento\Framework\App\Route\ConfigInterface.

C'est un peu comme dire:

"Hey Mr. ObjectManager! Chaque fois qu'une instance d'objet de type Magento\Backend\Model\Urlest demandée, veuillez d'abord regarder sa définition de constructeur de classe et analyser les dépendances qui y sont définies . Je veux que vous cherchiez ensuite à l'intérieur de la finale, fusionnée di.xmlde la requête HTTP actuelle, la configuration pour chaque dépendance configurée qui est définie dans le Magento \ Backend \ Model \ Url constructeur de la classe . Vous me donnez que la mise en œuvre de la dépendance configurée « .

adjco
la source