Dando prosseguimento aos nossos estudos de Dependency Injection, hoje falaremos sobre Magento 2 Virtual Types.
Virtual Types permite que você altere os argumentos de uma dependência injetável específica e altere o comportamento de uma classe específica. Isso permite que você use uma classe personalizada sem afetar outras classes que têm uma dependência do original.
Voltando a nosso módulo.
Em nosso controller, fizemos a seguinte modificação:
<?php namespace ForMage\Learning\Controller\Page; use Magento\Framework\App\Action\Context; use Magento\Framework\App\ResponseInterface; use ForMage\Learning\Api\SizeInterface; use ForMage\Learning\Api\ColorInterface; use ForMage\Learning\Model\Product\Shoe; use ForMage\Learning\Model\Product\Shirt; class Index extends \Magento\Framework\App\Action\Action { protected $size; protected $color; protected $product; protected $shirt; public function __construct( Context $context, SizeInterface $size, ColorInterface $color, Shoe $product, Shirt $shirt ) { parent::__construct($context); $this->size = $size; $this->color = $color; $this->product = $product; $this->shirt = $shirt; } public function execute() { var_dump($this->product); } }
Estamos dando um var_dump em nossa classe Shoe. Ao acessar a nossa rota, temos o seguinte resultado:
Ok. Mas como usamos o Virtual Types?
Magento 2 Virtual Types
O Virtual Types age como uma subclasse de uma classe específica, sem interferir em outras classes. É uma dependência numa classe existente que não afeta outras classes.
O que nós queremos, é adicionar uma dependência a nossa classe SizeGreat sem que isso afete outros classes.
Faremos as seguintes alterações:
Criamos uma nova interface:
<?php namespace ForMage\Learning\Api; interface MaterialInterface { public function getMaterial(); }
Adicionamos uma nova Model que implementa o MaterialInterface
<?php namespace ForMage\Learning\Model; use ForMage\Learning\Api\MaterialInterface; class MaterialSynthetic implements MaterialInterface { public function getMaterial() { return "Synthetic"; } }
Alteramos o nosso SizeGreat
<?php namespace ForMage\Learning\Model; use ForMage\Learning\Api\SizeInterface; use ForMage\Learning\Api\MaterialInterface; class SizeGreat implements SizeInterface { protected $material; public function __construct(MaterialInterface $material) { $this->material = $material; } public function getSize() { return "Great"; } }
O que fizemos nele foi adicionar o nosso MaterialInterface e instanciá-lo a partir do __construct() que criamos para a nossa classe.
Feito isso, voltamos ao nosso di.xml com as seguintes alterações:
<?xml version="1.0"?> <!-- /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> <preference for="ForMage\Learning\Api\SizeInterface" type="ForMage\Learning\Model\SizeSmall" /> <preference for="ForMage\Learning\Api\ColorInterface" type="ForMage\Learning\Model\ColorWhite" /> <preference for="ForMage\Learning\Api\MaterialInterface" type="ForMage\Learning\Model\MaterialSynthetic" /> <virtualType name="typeMaterial" type="ForMage\Learning\Model\SizeGreat"> <arguments> <argument name="material" xsi:type="object">ForMage\Learning\Model\MaterialSynthetic</argument> </arguments> </virtualType> <type name="ForMage\Learning\Model\Product\Shoe"> <arguments> <argument name="color" xsi:type="object">ForMage\Learning\Model\ColorBlack</argument> <argument name="size" xsi:type="object">typeMaterial</argument> </arguments> </type> <type name="ForMage\Learning\Model\Product\Shirt"> <arguments> <argument name="typeText" xsi:type="string">MY STRING IN ARGUMENT TYPE</argument> <argument name="typeNumber" xsi:type="number">19.80</argument> <argument name="typeArray" xsi:type="array"> <item name="customName" xsi:type="string">Antonio da Silva</item> <item name="customColor" xsi:type="string">Purple</item> </argument> <argument name="typeInitParameter" xsi:type="init_parameter">ForMage\Learning\Model\Product\Shirt::MY_CONSTANT</argument> </arguments> </type> </config>
Explicando:
Apontamos a nossa interface MaterialInterface para a classe concreta MaterialSynthetic:
<preference for="ForMage\Learning\Api\MaterialInterface" type="ForMage\Learning\Model\MaterialSynthetic" />
Adicionamos o nosso Virtual Types. Através dele, estamos informando que a classe SizeGreat tem uma dependência com a classe MaterialSynthetic
<virtualType name="typeMaterial" type="ForMage\Learning\Model\SizeGreat"> <arguments> <argument name="material" xsi:type="object">ForMage\Learning\Model\MaterialSynthetic</argument> </arguments> </virtualType>
virtualType name”typeMaterial” –> O nome do nosso virtual type
type=”ForMage\Learning\Model\SizeGreat” –> a classe que estamos atacando, adicionando a nossa dependência.
Alteramos o nosso argument type em:
<type name="ForMage\Learning\Model\Product\Shoe"> <arguments> <argument name="color" xsi:type="object">ForMage\Learning\Model\ColorBlack</argument> <argument name="size" xsi:type="object">typeMaterial</argument> </arguments> </type>
Em parâmetro name=”size” nós alteramos, chamando o nosso virtual types typeMaterial.
Após isso, ao executarmos a nossa rota novamente teremos:
Dúvidas? Posta aí!
Um abraço!