Instância do Magento 2 Helper

11

Quando eu acho que envolvi o sistema DI do Magento 2, algo aparece e o quebra.
Vejo no código principal maneiras diferentes de acessar um auxiliar.
Por exemplo, Magento\Catalog\Controller\Category::_initCategoryexiste isso:

if (!$this->_objectManager->get('Magento\Catalog\Helper\Category')->canShow($category)) {
    return false;
}

Mas no Magento\Catalog\Block\Category\Viewajudante é injetado no construtor

public function __construct(
    \Magento\Framework\View\Element\Template\Context $context,
    \Magento\Catalog\Model\Layer\Category $catalogLayer,
    \Magento\Framework\Registry $registry,
    \Magento\Catalog\Helper\Category $categoryHelper,
    array $data = array()
) {
    $this->_categoryHelper = $categoryHelper;
    $this->_catalogLayer = $catalogLayer;
    $this->_coreRegistry = $registry;
    parent::__construct($context, $data);
}

Isso me levou a pensar que os auxiliares deveriam ser acessados ​​de maneira diferente em controladores e blocos (e modelos), mas então encontrei um controlador em que um auxiliar é injetado no construtor Magento\Catalog\Controller\Adminhtml\Product\Action\Attribute.

Por favor, limpe o nevoeiro para mim.
Quando devo usar DI e quando devo usar objectManager? e porque?
Eu li esta pergunta: Instanciando auxiliares no Magento 2 . Esta é apenas uma pergunta de acompanhamento sobre isso.

Marius
fonte

Respostas:

10

Eu preferiria o DI sempre que possível, pois o uso do gerenciador de objetos já é uma violação à lei do demeter. Ao usar o gerenciador de objetos, essas dependências ficam ocultas na lógica do método.

Tobias
fonte
Sim. Concordo. Vou usar DI, mas estou curioso para saber por que isso é feito no núcleo? Talvez alguém ainda não tenha refatorado as aulas que mencionei?
Marius
Afaik eles ainda estão refatorando muito e espero que eles também toquem nesses lugares. Mas também não sabem sobre as prioridades, que precisam existir se quiserem realmente ser lançadas em algum momento. Portanto, talvez alguns novos recursos ou outras práticas ruins sejam corrigidos primeiro.
Tobias
E se você tiver classe de 10 funções e APENAS 1 função exigir modelo específico? Não seria redundante (do ponto de vista de desempenho) carregar o modelo através da injeção do construtor para cada uma das 10 funções, enquanto poderíamos carregá-lo usando o gerenciador de objetos apenas dentro de uma única função?
JohnyFree
6

Não sei muito sobre a implementação do Magento, mas parece que ObjectManageré um localizador de serviço .

Geralmente, o uso de um Localizador de Serviço para acessar dependências em um objeto é bastante ruim, confira este artigo .

Definir explicitamente suas dependências através de um construtor é uma abordagem muito melhor. Ajuda nos testes de unidade e nos problemas de tempo de execução, com os serviços não sendo definidos.

Injetar o Gerenciador de Objetos em uma classe é basicamente injetar um Registro em sua classe que tenha acesso a todos os serviços de seus aplicativos, o que obviamente não está certo.

Eu uso o ZF2 um pouco e geralmente defino pequenas classes de fábrica para Serviços, Controladores e qualquer classe que exija dependências. Essas classes de fábrica têm acesso ao Localizador de serviços e agarram todos os serviços dos quais o objeto depende e os injetam através do construtor. Usar um Localizador de Serviço em uma classe Factory é bom, pois é na maioria das vezes descartável, algo como isso, por exemplo.

Essas fábricas ainda são fáceis de testar .

IMO, use injeção de construtor sempre que possível. Novamente, eu não sei muito sobre a implementação do Magento e se ele tem o conceito de Fábricas, a partir de uma rápida olhada, parece que ele as suporta, mas definir explicitamente suas classes e usar um Localizador de Serviço para construí-las nas classes Factory é uma abordagem muito mais limpa.

Isto é de alguém que tem exposição limitada aos padrões mencionados acima, então eu também gostaria de ouvir os pensamentos / experiências de outras pessoas sobre o assunto!

Mais leitura

Aydin Hassan
fonte
Obrigado pela boa explicação. Minha pergunta foi "Por que existem duas maneiras de acessar um auxiliar no núcleo?" então isso é um pouco fora de tópico, mas tirou algumas outras dúvidas que eu tinha. :) Obrigado.
Marius
Eu provavelmente diria que é apenas algo que ainda não foi refatorado. Ou isso ou pode ser uma coisa fácil de usar. Exigir que os consumidores injetem sempre todas as suas dependências em um Controlador pode ser visto como contraproducente, especialmente ao executar o RAD. Oferecer aos consumidores as duas maneiras de acessar dependências permitiria a abordagem RAD, mas ainda permitiria que outros definissem explicitamente suas dependências, se assim o desejassem.
Aydin Hassan
5

Uma outra maneira de usar o auxiliar (nos modelos) é:

$this->helper('[Vendor]\[Module]\Helper\[Helper Name]')->getMethodName();

Espero que seja útil se você ainda não sabia.

rbncha
fonte
isso é semelhante ao uso do gerenciador de objetos. Não tenho certeza se é a melhor ideia.
Marius
1
O método acima é apenas para modelos, tanto quanto eu sei. Gerente de objeto é utilizado em controladores, blocos, modelos etc.
rbncha
1
Não está no mesmo estádio que o código, porque não há dependências de código nos modelos. Os modelos são apenas consumidores e não poluem nenhum cliente com encapsulamento quebrado.
21417 demonkoryu
Não sei o que demonkoryu está tentando dizer. Mas a melhor maneira de chamar o auxiliar de qualquer módulo é esta. Este é o Magento. Como se costuma dizer, todo código de bloco / seção deve ser chamado / modificável sem tocar no núcleo. Então, tudo está inter-relacionado ou tem dependências.
rbncha
2

Embora seja uma pergunta antiga, não tenho certeza se Marius recebeu sua resposta. Acredito que Marius possa responder melhor. Eu gostaria de responder em resumo. Por que o Magento 2 sugere usar DI em vez de auxiliar?

  • Tornando possível / fácil o isolamento em testes de unidade
  • Definindo explicitamente dependências de uma classe
  • Facilitar o bom design (princípio de responsabilidade única (SRP), por exemplo)
  • O uso de DI no seu módulo reduz o risco de erros de incompatibilidade quando o Magento altera a implementação subjacente dessas interfaces. Este é um conceito importante para entender para desenvolvedores de extensão.

Por que o núcleo M2 pode não usar DI em alguns casos?

  • Número decrescente de classes
  • Não criando interfaces desnecessárias
  • Sem risco de erros de incompatibilidade

Embora o módulo de catálogo Core tenha sido usado como auxiliar, ele utilizou DI extensivamente. Em minha pesquisa, descobri que o Magento 2 utilizava poucas funções nos arquivos auxiliares do Catálogo Principal que não são adequadas para Contratos de Serviço.

Se você precisar usar explicitamente uma classe definida pelo Magento (como \ Magento \ Catalog \ Model \ Product), torne a dependência implícita explícita, dependendo da implementação concreta em vez da interface do contrato de serviço.

Sem dúvida, o desenvolvedor de extensões deve usar DI em vez de Magento1 como Helper. Ao implementar de acordo com as diretrizes do Magento 2, as consequências são limitadas. Ao quebrar as recomendações, problemas acontecem.

Agilox
fonte
Sim, eu recebi minha resposta enquanto isso. Mas obrigado por reservar um tempo para responder. Esta é uma informação valiosa para as pessoas que pesquisam isso online.
Marius