How to use type and virtual type declarations to add constructor arguments using dependency injection in Magento 2
Types and virtual types are another great feature of Magento 2 which allows developers to modify and extend existing code without rewriting or customizing the native or 3rd party code.
Both type and virtual type magic is rooted in the dependency injection pattern. Object manager is able to inject the defined arguments during class creation. Lets start with an example on how this can be done.
Type
<type name="Magento\CatalogSearch\Model\Layer\Category\ItemCollectionProvider">
<arguments>
<argument name="collectionFactory" xsi:type="object">Magento\CatalogSearch\Model\ResourceModel\Fulltext\CollectionFactory</argument>
</arguments>
</type>
In this example Magento\CatalogSearch\Model\ResourceModel\Fulltext\CollectionFactory class is passed in as collectionFactory argument. Important things to keep in mind:
- The argument name must match the class constructor parameter
- All instances of class Magento\CatalogSearch\Model\Layer\Category\ItemCollectionProvider will now be using the new collectionFactory argument
Virtual type
<virtualType name="Magento\Backend\Model\Auth\Session\Storage" type="Magento\Framework\Session\Storage">
<arguments>
<argument name="namespace" xsi:type="string">admin</argument>
</arguments>
</virtualType>
Virtual types are very similar to types but provide additional flexibility because they allow us to define a virtual class. If you take a look at the type defined above:
- The type should be the class that we would like to base our virtual class on
- The argument name should match the type class constructor same as for regular type declaration
- Magento\Backend\Model\Auth\Session\Storage is not an actual class that exists. There is no file that defines this class. The class is automatically generated by dependency injection. The class is later used an a constructor argument for backen session class
So virtual type allows us to dynamically generate classes that are based on other existing classes and change the arguments without affecting the original dependencies. This is an amazing feature that gives great flexibility to avoid duplicate and unnecessary code.
Bonus tip
Passing in arguments this way also allows us to implement features that are easily extendable. A great example for this can be seen in our previous article on Global Search. The global search allows us to define our own search modules which are later processed by the native functionality. Here is a quick look on how this works
<type name="Magento\Backend\Controller\Adminhtml\Index\GlobalSearch">
<arguments>
<argument name="searchModules" xsi:type="array">
<item>
...
</item>
</argument>
</arguments>
</type>
This allows us to provide a way for other developers to hook into our functionality without having to change any behind the scenes logic.
Hopefully this gives you an idea on how to use types and virtual types and how they differ.