Magento 2 não suporta injeção de dependência em características?


8

As características realmente funcionam com injeção de dependência no Magento? Considere o seguinte código:

Classe de Características

namespace Frame\Slick\Block;
use Frame\Slider\Slick\Block\Data as Helper

trait Slick
{
   protected $_slickHelper;
   public function __construct(Helper $slickHelper) 
   {
     $this->_slickHelper = $slickHelper;
   }
}

Classe usando a característica

namespace Frame\Slick\Block;

class Product ListProduct implements BlockInterface 
{
   use Slick;
   public function testTrait()
   {
      return $this->_slickHelper->getHelloWorld();
   }
}

Parece sempre retornar nulo, tenho certeza de que tudo está sendo incluído corretamente. A característica pode realmente suportar a injeção de dependência?

EDIT: Por exemplo, se você fizer um di no construtor de características e atribuí-lo a uma variável de característica e depois a chamar na classe que usa a característica, ela sempre retornará nulo. Qualquer outra coisa funciona bem.


Apenas uma pergunta ... "testTrait ()" retorna nulo ou "$ this -> _ slickHelper" é nulo?
— Phoenix128_RiccardoT

$ this -> _ slickHelper retorna nulo, outros métodos no trabalho de característica apenas di atribuídos a variáveis ​​de característica não funcionam.
— André Ferraz

11
Boa pergunta. Suponho que o Magento use o Reflection para inspecionar os argumentos do construtor, e isso funciona bem com as características: 3v4l.org/jbVTU - mas eu precisaria dar uma olhada na geração de código para verificar isso.
— Fabian Schmengler

mas por que você deseja usar traços? Você pode dar um exemplo da vida real? Talvez exista uma maneira mais simples de contornar isso
— Marius

@ Marius Criei este módulo que funciona como um controle deslizante para CMS Blocks, Cross sells, Products (de uma categoria específica) e up sells. Cada uma dessas classes de bloco estende outra classe, por exemplo, produtos estende o Magento \ Catalog \ Block \ Product \ ListProduct. Realmente, a razão pela qual estou usando traços é porque resolve o "problema" da arquitetura de herança única do PHP. Dessa forma, há menos repetição de código.
— André Ferraz

Respostas:


2

Eu testei usando característica e funciona bem.

Aqui está a aparência da minha característica:

<?php

namespace ProjectName\ModuleName\Controller\Adminhtml;

use Magento\Backend\App\Action\Context;
use ProjectName\ModuleName\Model\ResourceModel\Distributor\CollectionFactory as DistributorCollectionFactory;

trait DistributorTrait
{
    protected $distributorCollectionFactory;

    public function __construct(
        Context $context,
        DistributorCollectionFactory $distributorCollectionFactory
    )
    {
        parent::__construct($context);

        $this->distributorCollectionFactory = $distributorCollectionFactory;
    }
}

Eu o uso no controlador assim:

<?php

namespace ProjectName\ModuleName\Controller\Adminhtml\Distributor;

use Magento\Backend\App\Action;
use ProjectName\ModuleName\Controller\Adminhtml\DistributorTrait;

class Index extends Action
{
    use DistributorTrait;

    public function execute()
    {
        dump($this->distributorCollectionFactory->create()->getItems());exit;
    }
}

E aqui está o resultado:

Resultado do teste de característica


0

Eu só estava enfrentando isso. A postagem original é bem antiga, então as coisas podem ser diferentes agora do que quando foi postada, no entanto, o que descobri é que o construtor DI funciona, mas tem uma grande ressalva.

Se eu usar a seguinte característica no meu código:

<?php

namespace My\Module\Util;

use Psr\Log\LoggerInterface;

trait LoggerTrait
{
    protected $logger;

    public function __construct(
        LoggerInterface $logger
    ) {
        $this->logger = $logger;
    }

    /**
     * @return Logger
     */
    public function getLogger()
    {
        return $this->logger;
    }

    /**
     * @param Logger $logger
     */
    public function setLogger($logger)
    {
        $this->logger = $logger;
    }
}

e prossiga para usar essa característica em uma classe:

<?php

namespace My\Module;

use \My\Module\Util\LoggerTrait;

class Service
{
    use LoggerTrait;

    public function doSomething() {
        $this->getLogger()->log('Something was done!');
    }
}

A interface do logger é injetada perfeitamente e tudo funciona bem. No entanto, se eu quiser injetar minhas próprias classes na minha classe Service usando o método construtor. Por exemplo:

<?php

namespace My\Module;

use \My\Module\Util\LoggerTrait;


class Service
{
    use LoggerTrait;

    public function __construct(
         \Some\Other\Class $class
    ) {
        $this->other = $class;
    }


    public function doSomething() {
        $this->getLogger()->log('Something was done!');
    }
}

Nesse caso, o método construtor da minha característica nunca é chamado, o que significa que a propriedade $ logger da minha classe nunca é definida. É certo que eu não usei muito os traços, por isso meu conhecimento é meio limitado, mas minha suposição é que isso ocorre porque minha classe substituiu o método construtor do meu traço. Isso é praticamente uma rolha de exibição, já que a maior parte da base de código Magento usa construtores para injetar dependências, descartando afetivamente seu uso em características.

A única solução real que posso ver é usar o ObjectManager diretamente para injetar suas dependências de características:

<?php

namespace My\Module\Util;

use Psr\Log\LoggerInterface;

trait LoggerTrait
{
    protected $logger;


    /**
     * @return Logger
     */
    public function getLogger()
    {
        if (is_null($this->logger)) {
            $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
            $this->logger = $objectManager->create('Psr\Log\LoggerInterface');
        }
        return $this->logger;
    }

    /**
     * @param Logger $logger
     */
    public function setLogger($logger)
    {
        $this->logger = $logger;
    }
}

Isenção de responsabilidade: O uso do ObjectManager no Magento geralmente é desencorajado, mas pelo que posso ver neste caso, é a única opção real. No meu exemplo, se você quiser definir uma interface de logger diferente em sua classe, ainda poderá fazê-lo injetando-a em seu construtor e substituindo a propriedade $ logger das classes.


Na sua classe, você declarou 2 __construct, que é um importado do traço e o outro na própria classe. No entanto, você não pode ter 2 métodos com o mesmo nome na classe única. Então, basicamente, no seu caso, __constructa característica é substituída pela __constructprópria classe.
— Rendy Eko Prastiyo
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.