DI & Estendendo um bloco no Magento 2

15

Parece que estou lutando para entender a injeção de dependência do Magento 2 com blocos, toda vez que tento estender um bloco que não é \ Magento \ Framework \ View \ Element \ Template, acabo com erros.

Eu quero criar um bloco que estenda a classe de bloco muito básica do Magento \ Theme \ Block \ Html \ Header \ Logo - tudo funciona bem até que eu tente a injeção de dependência no método de construção:

<?php

namespace Creare\Test\Block\Header;

class Logo extends \Magento\Theme\Block\Html\Header\Logo
{

    protected $_creareHelper;

    public function __construct(
        \Magento\Framework\View\Element\Template\Context $context,
        \Creare\Seo\Helper\Data $creareHelper,
        array $data = []
    )
    {
        $this->_creareHelper = $creareHelper;
        parent::__construct($context, $data);
    }
}

Assim que tento injetar minha classe auxiliar (ou qualquer outra coisa, recebo um rastreamento de pilha começando com o seguinte erro:

Recoverable Error: Argument 2 passed to Magento\Theme\Block\Html\Header\Logo::__construct() must be an instance of Magento\MediaStorage\Helper\File\Storage\Database, array given, called in /Users/adammoss/PhpstormProjects/Magento2/app/code/Creare/Test/Block/Header/Logo.php on line 17 and defined in /Users/adammoss/PhpstormProjects/Magento2/app/code/Magento/Theme/Block/Html/Header/Logo.php on line 33

Se eu adicionar as mesmas dependências ao meu __construct como o arquivo que estou estendendo, funciona, mas certamente essa é uma maneira inversa de fazer as coisas, pois o ponto da herança de classe é que absorvo todos os métodos e propriedades dos pais?

Eu acho que só preciso de uma explicação básica de alguém para estender as aulas e usar DI com Magento 2. Qualquer ajuda muito apreciada!

Adam Moss
fonte
"certamente essa é uma maneira inversa de fazer as coisas" concordou.
James

Respostas:

19

A classe que você está tentando estender possui este construtor:

public function __construct(
    \Magento\Framework\View\Element\Template\Context $context,
    \Magento\MediaStorage\Helper\File\Storage\Database $fileStorageHelper,
    array $data = []
) {
    $this->_fileStorageHelper = $fileStorageHelper;
    parent::__construct($context, $data);
}

então você precisa fazer o seu construtor ficar assim

public function __construct(
    \Magento\Framework\View\Element\Template\Context $context,
    \Magento\MediaStorage\Helper\File\Storage\Database $fileStorageHelper,
    \Creare\Seo\Helper\Data $creareHelper,
    array $data = []
)
{
    $this->_creareHelper = $creareHelper;
    parent::__construct($context, $fileStorageHelper, $data);
}

Conclusão ...
Nas classes filho, você precisa especificar todos os parâmetros do construtor da classe pai, além dos novos parâmetros. Não acho que a ordem seja importante e não sei qual é a melhor prática.
Em seguida, no construtor, você atribui seus novos objetos injetados aos vars membros e chama o construtor pai com o mesmo número de parâmetros necessários.

Marius
fonte
2
Isso faz sentido, obrigado pela sua resposta. Acho que só esperava que fosse mais elegante que isso.
Adam Moss
A ordem de argumentos @Marius precisa ser igual aos argumentos do método __construct da classe pai, seus argumentos personalizados precisam passar no final.
Chirag dodia #
@chiragdodia Por quê? Acho que não. Tudo o que construí até agora no M2 construí usando os argumentos de construção personalizados adicionados aleatoriamente. E funcionou. a única restrição é que os argumentos com um valor padrão devam durar por último.
Marius
@ Marius sim, está funcionando em alguns casos, mas no meu caso, quando estendi \ Magento \ Catalog \ Block \ Product \ View não está funcionando, preciso fazer a mesma ordem de argumentos que no construtor pai e adicionar argumentos personalizados, finalmente. Dê uma olhada no meu código aqui magento.stackexchange.com/questions/95697/…
chirag dodia
Ele não está funcionando para mim quando tentei substituir o bloco \ Magento \ Customer \ Block \ Form \ Register
DEEP JOSHI