Magento, Magento 2

Virtual Types in Magento 2

Virtual Type In Magento 2

Virtual types are a way to inject different dependencies into existing PHP classes without affecting other classes and without having to create a new class file. 

Hello Everyone, welcome to my blog. Today, I am going to discuss the virtual types in Magento 2. In this blog, we will see how can we declare the Virtual types in Magento 2 using di.xml,  what is the use of Virtual types and, in which situation we should use virtual types.

Virtual Types

As per the definition of the virtual type implies, the class is not present in any of the Magento files and it’s not generated at the time of Object creation. Virtual type can be preferred as the link to the class which helps to replace the constructor argument.

Magento introduces the argument replacement functionality to change the parameters of the constructor at any given time of moment when the particular class gets called. There are two types of argument replacement nodes provided by Magento.

  1. Type
  2. Virtual Type

Type Node in Magento 2

The type node is defined inside the di.xml file and is used to change the constructor parameter using an object manager at the time object creation.

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Core\Model\Session">
        <arguments>
            <argument name="sessionName" xsi:type="string">adminhtml</argument>
        </arguments>
    </type>
</config>

Here, we have two attributes inside the argument node, first one is the name, it must match with the actual argument pass to the constructor class i.e. Magento\Core\Model\Session and the second one id type, which is the data type of the argument. The argument types are given below.

  1. String
  2. Boolean
  3. array
  4. Number
  5. Init_parameter
  6. Const
  7. Null

Virtual Type Node in Magento 2

Virtual type nodes are defined in a di.xml file like.

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <virtualType name="moduleConfig" type="Magento\Core\Model\Config">
        <arguments>
            <argument name="type" xsi:type="string">system</argument>
        </arguments>
    </virtualType>
    <type name="Magento\Core\Model\App">
        <arguments>
            <argument name="config" xsi:type="object">moduleConfig</argument>
        </arguments>
    </type>
</config>

Create a Virtual type means creating a subclass. From the above example, we can figure out that moduleConfig is a subclass of Magento\Core\Model\Config and its actual implementation will be like this(at the time of object creation on the fly).

Class moduleConfig extends Magento\Core\Model\Config {
}

But, when we are creating an actual class, we need to pull all the constructor dependencies of its parent class, instead, in a virtual class, we don’t need to define all the dependencies of the parent constructor. We just need to pass the argument that we need to replace. For example, we have class A having 10 dependencies and we just want to change one argument, so instead of overriding that class and changing the constructor parameter we can use Virtual type and we don’t need to care about its dependencies(that will be handled by the ObjectManager). 

Using Virtual Type in Magento 2

Let’s create a class CarsShowroom which will have all the list of our car. I have created a simple module to demonstrate the Virtual type. I have created a controller and a route for demonstration purposes if you want to know more about how to create a controller and a route please check out my previous blog here

<?php
namespace Ashish\VirtualTypeDemo\Model;
class CarsShowroom
{
   public $carsList;

   /**
    * Argument1 constructor.
    * @param array $carsList
    */
   public function __construct(array $carsList = [])
   {
       $this->carsList = $carsList;
   }
}

Then I have create cars class which will hold our cars brand i.e.

<?php
namespace Ashish\VirtualTypeDemo\Model;
class Cars
{
   public $cars;
   public function __construct(array $cars = [])
   {
       $this->cars = $cars;
   }
}

Then I have created a virtual type in di.xml file 

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <virtualType name="FirstList" type="Ashish\VirtualTypeDemo\Model\Cars">
        <arguments>
            <argument name="cars" xsi:type="array">
                <item name="audi" xsi:type="string">Audi</item>
                <item name="mercedes" xsi:type="string">Mercedes</item>
            </argument>
        </arguments>
    </virtualType>

    <virtualType name="SecondList" type="Ashish\VirtualTypeDemo\Model\Cars">
        <arguments>
            <argument name="cars" xsi:type="array">
                <item name="bmw" xsi:type="string">BMW</item>
                <item name="jaguar" xsi:type="string">Jaguar</item>
            </argument>
        </arguments>
    </virtualType>
    <type name="Ashish\VirtualTypeDemo\Model\CarsShowroom">
        <arguments>
            <argument name="carsList" xsi:type="array">
                <item name="FirstList" xsi:type="object">FirstList</item>
                <item name="SecondList" xsi:type="object">SecondList</item>
            </argument>
        </arguments>
    </type>
</config>

Now, in the di.xml file, I have created two virtual types i.e. FirstList and SecondList. From its arguments, I have added the cars brand name into the class Ashish\VirtualTypeDemo\Model\Cars which is having the constructor parameter cars which is an array type. If we need to write these classes in a PHP way that would look like this.

<?php 
Class FirstList extends \Ashish\VirtualTypeDemo\Model\Cars
{
	public function __construct(array $cars = [])
        {
	    $cars = array(‘audi’ => ‘Audi’, ‘mercedes’=> ‘Mercedes’);
	    parent::__construct($cars);   	
        }

}
<?php 
Class SecondList extends \Ashish\VirtualTypeDemo\Model\Cars
{
	public function __construct(array $cars = [])
        {
	    $cars = array(‘bmw’ => ‘BMW’, ‘jaguar’=> ‘Jaguar’);
	    parent::__construct($cars);   	
        }

}

Virtual type allows us to change the parameter on the fly, and we no need to care about the class creation. But, we cannot use the virtual type as a constructor parameter in any extension class(constructor dependency like normal classes) and we can not override the virtual class also.

To check the output of the above class you can create an object of CarsShowroom class and print object vars. You will get the following output.

array(1) {
  ["carsList"]=>
  array(2) {
    ["FirstList"]=>
    object(Ashish\VirtualTypeDemo\Model\Cars)#1040 (1) {
      ["cars"]=>
      array(2) {
        ["audi"]=>
        string(4) "Audi"
        ["mercedes"]=>
        string(8) "Mercedes"
      }
    }
    ["SecondList"]=>
    object(Ashish\VirtualTypeDemo\Model\Cars)#1038 (1) {
      ["cars"]=>
      array(2) {
        ["bmw"]=>
        string(3) "BMW"
        ["jaguar"]=>
        string(6) "Jaguar"
      }
    }
  }
}

If you want to know more about argument replacement, please check out this link here.  Let me know what you think about this blog. Goodbye for now and happy coding 🙂

Tagged ,

3 thoughts on “Virtual Types in Magento 2

  1. Thanks for finding time to share this kind of valuable information. I am very new to Magento, and was desperately searching for in-depth articles with simple examples for Virtual Types. I can’t say I understand it fully, but I grabbed good amount of it.

    Keep writing Ashish 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *

*

code