Question

I am trying to understand the virtual type with the help of existing blog and video tutorial. It's too hard to understand the concept and it's too confused

Here I'want some good understandable example to understand virtual type and that will guide me to use in my real time custom module.

Thanks in advance for your better support

Was it helpful?

Solution

VirtualType's are awesome! They allow to re-use code rather than replicating. The more

Let's pretend you had a sandwich shop. Your principal PHP class is called Sandwiches and you need to feed it 3 different sandwiches to present in a menu. One sandwich for carnivores, one for pescatarians, and one for vegans. All sandwiches use the same basic construction of a Main Ingredient and a Bread type - so you don't want to create 3 separate PHP classes for each type.

<?php

declare(strict_types=1);

class Sandwiches
{
    /**
     * @var \SandwichInterface
     */
    private $meatSandwich;

    /**
     * @var \SandwichInterface
     */
    private $fishSandwich;

    /**
     * @var \SandwichInterface
     */
    private $veganSandwich;

    /**
     * Sandwiches constructor.
     *
     * @param \SandwichInterface $meatSandwich
     * @param \SandwichInterface $fishSandwich
     * @param \SandwichInterface $veganSandwich
     */
    public function __construct(
        SandwichInterface $meatSandwich,
        SandwichInterface $fishSandwich,
        SandwichInterface $veganSandwich
    ) {
        $this->hamSandwich    = $meatSandwich;
        $this->salamiSandwich = $fishSandwich;
        $this->tunaSandwich   = $veganSandwich;
    }

    /**
     * @return array|\SandwichInterface[]
     */
    public function getAllSandwiches(): array
    {
        return [
            $this->meatSandwich,
            $this->fishSandwich,
            $this->veganSandwich
        ];
    }
}

Now, you'll need a generic Sandwich class that you can configure.

<?php

declare(strict_types=1);

class Sandwich implements \SandwichInterface
{
    /**
     * @var string
     */
    private $mainIngredient;

    /**
     * @var string
     */
    private $breadType;

    /**
     * Sandwich constructor.
     *
     * @param string $mainIngredient
     * @param string $breadType
     */
    public function __construct($mainIngredient, $breadType)
    {
        $this->mainIngredient = $mainIngredient;
        $this->breadType = $breadType;
    }

    /**
     * @return string
     */
    public function getMainIngredient(): string
    {
        return $this->mainIngredient;
    }

    /**
     * @return string
     */
    public function getBreadType(): string
    {
        return $this->breadType;
    }
}

Right now we have a simple Sandwich class that has no idea as to what type of ingredients are used. So how do we build our sandwiches? We need to configure it in di.xml.

To know:

  • In a virtualType, the "name" is fully arbitrary, it just needs to be unique
  • In a virtualType, the "type" refers to the concrete PHP class. In this case it is Sandwich
  • After you configure the sandwiches in di.xml, you will have 3 unique and shareable instances of Sandwich
  • The argument "name" needs to be exactly the same as the constructor argument name. So $mainIngredient is used in di.xml without the $ sign.

Let's make our sandwiches in di.xml

<virtualType name="YummyHamSandwich" type="Sandwich">
    <arguments>
        <argument name="mainIngredient" xsi:type="string">ham</argument>
        <argument name="bread" xsi:type="string">white</argument>
    </arguments>
</virtualType>

<virtualType name="DeliciousTunaSandwich" type="Sandwich">
    <arguments>
        <argument name="mainIngredient" xsi:type="string">tuna</argument>
        <argument name="bread" xsi:type="string">wheat</argument>
    </arguments>
</virtualType>

<virtualType name="UmmmItsAVeganSandwich" type="Sandwich">
    <arguments>
        <argument name="mainIngredient" xsi:type="string">tomato</argument>
        <argument name="bread" xsi:type="string">sourdough</argument>
    </arguments>
</virtualType>     

At this point, our Sandwiches menu still doesn't have any sandwiches on it. We've just configured the sandwiches but we haven't written them on the menu. Here is how we add the sandwiches to the Sandwiches class.

Make note that we are passing the arbitrary virtualType name as the various argument values below. Each "name" represents a unique and new instance of the Sandwich class.

<type name="Sandwiches">
    <arguments>
        <argument name="meatSandwich" xsi:type="object">YummyHamSandwich</argument>
        <argument name="fishSandwich" xsi:type="object">DeliciousTunaSandwich</argument>
        <argument name="veganSandwich" xsi:type="object">UmmmItsAVeganSandwich</argument>
    </arguments>
</type>
Licensed under: CC-BY-SA with attribution
Not affiliated with magento.stackexchange
scroll top