Cursos Magento

Dependency Injection: entenda como funciona

,

Atualizado em 17 de setembro de 2020

Dependency Injection ou Injeção de dependência, é uma das grandes mudanças do Magento 2 e afeta diretamente a forma como criávamos módulos no Magento 1.

Como o nome sugere, é através desta técnica que podemos adicionar novas dependências a uma classe. Enquanto no Magento 1 nós estendíamos a classe que nosso módulo necessitava, no Magento 2 todas as classes que queremos utilizar podem ser passadas no construtor da classe por exemplo. Por sua vez, o Magento buscará as classes em seus devidos lugares.

Imagine que você criou uma nova classe no Magento e esta classe busca dados em um outro Helper (outra classe). Portanto ela dependerá deste helper em algum ponto. Se estivéssemos desenvolvendo para Magento 1, bastaria chamar nosso helper com Mage::helper em qualquer lugar.

No entanto, no Magento 2, devemos primeiro buscar as classes e objetos que vamos usar em nossa classe. E isso faz muito sentido, não é mesmo? Antes de construir a casa, precisamos desenhar a planta, e conseguir o material para construção.

Veja o exemplo de injeção de dependência abaixo:

namespace Magento\Backend\Model\Menu;
class Builder
{
    /**
     * @param \Magento\Backend\Model\Menu\Item\Factory $menuItemFactory
     * @param \Magento\Backend\Model\Menu $menu
     */
    public function __construct(
        Magento\Backend\Model\Menu\Item\Factory $menuItemFactory, // Service dependency
        Magento\Backend\Model\Menu $menu // Service dependency
    ) {
        $this->_itemFactory = $menuItemFactory;
        $this->_menu = $menu;
    }
}

Note que nas linhas 9 e 10 as classes Magento\Backend\Model\Menu\Item\Factor e Magento\Backend\Model\Menu são injetadas na classe, e em seguida associadas e disponibilizadas nas propriedades _itemFactory e _menu.

As classes serão automaticamente inseridas pelo ObjectManager no começo do processo de carregamento do Magento.

Este é o tipo de injeção de dependência mais comum e mais utilizado, que é chamado Injeção de Construtor.

No entanto, existem outros 2 tipos de injeção de dependências no Magento. Vamos revisar os 3 tipos:

  • Injeção de Construtor (Constructor Injection): o mais comum e mais usado no Magento, como vimos acima. Para usá-lo basta adicionar a classe ou dependência que queremos no construtor da classe.
  • Setter Injection: Neste caso apenas adicionamos um setter na classe que recebe uma dependência.
  • Injeção via Inteface (Interface Injection): usa classes do tipo Interface para fazer injeção de dependências.

Brincando com Dependency Injection

Quando digitamos bin/magento no console, temos uma lista de comandos disponíveis. Para fins de teste e didáticos sempre crio um novo comando para testar algo ou mesmo demonstrar alguma coisa.

A lista de comandos disponíveis é montada através de injeção de dependência via interface. Portanto, para adicionar um novo comando à lista, precisamos realizar uma injeção de dependência.

Criando um comando no bin/magento

Assumindo que você já criou um módulo base Magento 2, vamos adicionar o seguinte arquivo em nosso módulo:

namespace Magenteiro\BaseModule\Console\Command;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class TestCommand extends Command
{
    protected function configure()
    {
        $this->setName('magenteiro:test:di')
            ->setDescription('Mostra Injeção de dependências');
        parent::configure();
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $output->writeln('Teste');
    }
}

Em seguida, vamos adicionar um arquivo em etc/di.xml e injetar esta classe no array commands da classe Magento\Framework\Console\CommandListInterface:

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Framework\Console\CommandListInterface">
        <arguments>
            <argument name="commands" xsi:type="array">
                <item name="magenteiroTest" xsi:type="object">Magenteiro\BaseModule\Console\Command\TestCommand</item>
            </argument>
        </arguments>
    </type>
</config>

Se você abrir a classe Magento\Framework\Console\CommandListInterface, ficará fácil descobrir qual dos 3 tipos de Injection estamos usando aqui, não é mesmo?

namespace Magento\Framework\Console;
interface CommandListInterface
{
    /**
     * Gets list of command instances
     *
     * @return \Symfony\Component\Console\Command\Command[]
     */
    public function getCommands();
}

Com isso já podemos chamar nosso comando no terminal.

Dependency Injection de Construtor

Vamos supor que nossa classe agora precise da classe \Magento\Framework\Filter\FilterManager para alguma coisa.
Basta adicionar a chamada dela a um método __construct. Ficaria assim:

public function __construct(
    \Magento\Framework\Filter\FilterManager $filterManager
) {
    $this->filterManager = $filterManager;
    parent::__construct(null);
}

Desta vez eu não preciso sequer mexer no di.xml, e já posso sair usando minha classe.

protected function execute(InputInterface $input, OutputInterface $output)
{
    $output->writeln('Teste');

    //limita uma string grande a 10 caracteres
    $stringLonga = "Lorem Ipsum is simply dummy text of the printing and typesetting";
    $output->writeln($this->filterManager->truncate($stringLonga, ['length'=> 10]));
}

Substituindo classe usando Dependency Injection: a beleza começa aqui

Note que a classe que passamos para o nosso construtor é \Magento\Framework\Filter\FilterManager.
Se você adicionar um simples get_class($this->filterManager) na saída, poderá ver a classe que está sendo instanciada. Vejamos:

protected function execute(InputInterface $input, OutputInterface $output)
{
    $output->writeln(get_class($this->filterManager));
}
classe antes da injeção da dependency injection

Substituindo a dependência

Vamos supor que queremos substituir a classe acima por outra, pois este é um módulo do core do Magento, ou um módulo de terceiro.

Para isso, criarei um outro módulo, aqui chamado Magenteiro_Di. Nele criarei uma classe chamada FilterManager.php e um arquivo di.xml que dirá ao Magento para substituir o parâmetro $filterManager pela minha classe.

namespace Magenteiro\Di\Helper;

class FilterManager extends \Magento\Framework\Filter\FilterManager
{

}
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magenteiro\BaseModule\Console\Command\TestCommand">
        <arguments>
            <argument name="filterManager" xsi:type="object">Magenteiro\Di\Helper\FilterManager</argument>
        </arguments>
    </type>
</config>

Note que na linha 4 eu especifico o nome do argumento (variável) que eu quero substituir, passando o novo objeto como parâmetro.
Veja o que acontece antes e depois de habilitar meu novo módulo.

Não é bacana? Isso é só o começo.

Se desejar receber os arquivos dos módulos acima, ficar por dentro das novidades do Magenteiro preencha o formulário abaixo. Isso e muito mais você encontra no Magento 2: O Curso – o curso de desenvolvimento para Magento 2 do Magenteiro.

Imagem principal de Pixabay.

Últimos posts por Ricardo Martins (exibir todos)
Comentários

Deixe seu comentário

[fbcomments url="https://www.magenteiro.com/blog/magento-2/dependency-injection-no-magento2/"]