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.

André Ferraz
fonte
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

Rendy Eko Prastiyo
fonte
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.

Andrew Kett
fonte
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