Why some classes define injections in both their constructor and di.xml?
As stated in the documentation, in Magento 2, the di.xml
can be used to do the following:
You can configure the class constructor arguments in your
di.xml
in the argument node. The object manager injects these arguments into the class during creation. The name of the argument configured in the XML file must correspond to the name of the parameter in the constructor in the configured class.
In your case it's slightly complex I'm going to explain each argument one by one:
\Magento\Framework\App\Route\ConfigInterface $routeConfig
: this is an interface so it's not usable directly. The preference for this class is defined inapp/etc/di.xml
and it is theMagento\Framework\App\Route\Config
class\Magento\Framework\App\RequestInterface $request
: same goes for this class, the preference isMagento\Framework\App\Request\Http
\Magento\Framework\Url\SecurityInfoInterface $urlSecurityInfo
: same case here again withMagento\Framework\Url\SecurityInfo\Proxy
as the preference\Magento\Framework\Url\ScopeResolverInterface $scopeResolver
: here we start with the interesting bit. Inapp/etc/di.xml
a preference is defined for this interface and it is theMagento\Framework\Url\ScopeResolver
class. However, for theMagento\Backend\Model\Url
Magento 2 needs to use another class and thus it defines which class in thedi.xml
you posted soMagento\Backend\Model\Url\ScopeResolver
will be used.\Magento\Framework\Session\Generic $session
this is a normal class and thus can be used as it.\Magento\Framework\Session\SidResolverInterface $sidResolver
: back to an interface, the preference is still defined inapp/etc/di.xml
and it isMagento\Framework\Session\SidResolver\Proxy
\Magento\Framework\Url\RouteParamsResolverFactory $routeParamsResolverFactory
: this is a factory class so it can be used as it.\Magento\Framework\Url\QueryParamsResolverInterface $queryParamsResolver
: back to ourapp/etc/di.xml
and the preference isMagento\Framework\Url\QueryParamsResolver
\Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
: another case here where **a preference is defined inapp/etc/di.xml
and it isMagento\Framework\App\Config
.$scopeType
: here we only have a variable without any class in front of it. Your moduledi.xml
specifies thatMagento\Store\Model\ScopeInterface::SCOPE_STORE
should be used as the value of this variable.**\Magento\Backend\Helper\Data $backendHelper
: here we could have use that class as it. However here a proxy is used because this class is not necessarily being used (see this post for details about proxy classes: Magento 2: practical explanation of what is a proxy class? )\Magento\Backend\Model\Menu\Config $menuConfig
: we can use this class as it.\Magento\Framework\App\CacheInterface $cache
: another preference defined inapp/etc/di.xml
for this interface which isMagento\Framework\App\Cache\Proxy
\Magento\Backend\Model\Auth\Session $authSession
: same again here we could have used the class as it but we use a proxy class instead for lazy loading.\Magento\Framework\Encryption\EncryptorInterface $encryptor
: jumping to theapp/etc/di.xml
again and we findMagento\Framework\Encryption\Encryptor
as a preference\Magento\Store\Model\StoreFactory $storeFactory
: a factory so we can use it as it.\Magento\Framework\Data\Form\FormKey $formKey
: here we use a theMagento\Framework\Data\Form\FormKey\Proxy
proxy class again for lazy loading.array $data = []
: this one always comes last and is automatically defaulted to an empty array you can find more information here: Magento 2: what is the $data array constructor parameter?
To summarize
Globally, classes constructors parameters are interfaces or non instantiable classes. Thus di.xml
lets you tailor the dependencies you want to use for each class constructor. It's also valid for instantiable classes. For example a class constructor that takes a product class as a constructor argument. It can be tailored in the configurable product module so it takes a configurable product class instead as an argument.
It is important to understand the difference between definition of dependencies and configuration of dependencies.
Dependencies are not defined inside di.xml. Dependencies are defined inside the constructor of the respective class by specifying an interface, an abstract or a factory as the type of that specific dependecy, e.g. $routeConfig
is a dependency of type \Magento\Framework\App\Route\ConfigInterface
.
On the other hand, di.xml
is the place to configure the dependencies by using <preference/>
nodes and/or xpath:type/arguments/argument
nodes (sometimes coupled with more advanced configuration nodes like <virtualType/>
or <proxy/>
). Configuring a dependency simply means mapping an object's constructor argument to an implementation/object/concrete.
You want dependencies to be configurable via di.xml so that you can swap them and use a different implementation for a certain interface or argument under certain conditions (keep reading the example to understand what certain conditions is supposed to mean).
For example, when developing your extension you would first create a new class (we call this new class an implementation). Your new class implements the \Magento\Framework\App\Route\ConfigInterface
interface and it has inside its body a concrete functionality which honors the interface contract. Now starts the configuration part: in order to tell Magento to use your newly defined implementation you must configure this implementation as a dependecy for the object Magento\Backend\Model\Url
. You do this configuration inside the di.xml
files or your module. In this case you need to use the <preference/>
node to map the interface to your new implementation. Other times you would use the more granular xpath:type/arguments/argument
di.xml
node to map only specific arguments (a.k.a. dependencies, a.k.a interfaces) of a concrete to specific implementations. Now, your implementation will only be active as a dependency for the object \Magento\Backend\Model\Url
in certain conditions, e.g., in the code execution flow of the current application request an object of type Magento\Backend\Model\Url
is being created and it needs an implementation for the constructor defined dependency called $routeConfig
which is of type \Magento\Framework\App\Route\ConfigInterface
.
It is pretty much like saying:
"Hey Mr. ObjectManager! Whenever an object instance of type Magento\Backend\Model\Url
is requested, please have a look at its class constructor definition first and analyze the dependecies defined therein. I want you then to lookup inside the final, merged di.xml
of the current HTTP request the configuration for each and every configured dependency that is defined in the Magento\Backend\Model\Url class constructor. You give me that configured dependency implementation."