¿Magento 2 no admite la inyección de dependencia en rasgos?

8

¿Los rasgos realmente funcionan con la inyección de dependencia en Magento? Considere el siguiente código:

Clase de rasgo

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

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

Clase usando el rasgo

namespace Frame\Slick\Block;

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

Parece que esto siempre devuelve nulo, estoy muy seguro de que todo se incluye correctamente. ¿Puede el rasgo realmente apoyar la inyección de dependencia?

EDITAR: Por ejemplo, si hace un di en el constructor de rasgos y lo asigna a una variable de rasgo y luego lo llama a la clase que usa el rasgo, siempre devolverá nulo. Cualquier otra cosa funciona bien.

André Ferraz
fuente
Solo una pregunta ... ¿"testTrait ()" devuelve nulo o "$ this -> _ slickHelper" es nulo?
Phoenix128_RiccardoT
$ this -> _ slickHelper devuelve nulo, otros métodos en el rasgo funcionan solo los di asignados a las variables de rasgo no funcionan.
André Ferraz
1
Buena pregunta. Supongo que Magento usa Reflection para inspeccionar los argumentos del constructor y esto funciona bien con rasgos: 3v4l.org/jbVTU , pero tendría que echar un vistazo más de cerca a la generación de código para verificarlo.
Fabian Schmengler
pero ¿por qué quieres usar rasgos? ¿Puedes dar un ejemplo de la vida real? Tal vez hay una forma más simple de
evitarlo
@ Mario creé este módulo que actúa como un control deslizante para bloques CMS, ventas cruzadas, productos (de una categoría específica) y ventas superiores. Cada una de estas clases de bloques amplía otra clase, por ejemplo, los productos amplían Magento \ Catalog \ Block \ Product \ ListProduct. Realmente la razón por la que estoy usando rasgos es porque resuelve el "problema" de la arquitectura de herencia única de PHP. De esta manera hay menos repetición de código.
André Ferraz

Respuestas:

2

He probado usando rasgo y funciona bien.

Así es como se ve mi rasgo:

<?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;
    }
}

Lo uso en un controlador como este:

<?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;
    }
}

Y aqui esta el resultado:

Resultado de la prueba de rasgo

Rendy Eko Prastiyo
fuente
0

Estaba enfrentando esto yo mismo. La publicación original es bastante antigua, por lo que las cosas pueden ser diferentes ahora que cuando se publicó, sin embargo, lo que encontré es que el constructor DI funciona pero tiene una advertencia bastante grande.

Si uso el siguiente rasgo en mi 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;
    }
}

y luego proceder a usar ese rasgo en una clase:

<?php

namespace My\Module;

use \My\Module\Util\LoggerTrait;

class Service
{
    use LoggerTrait;

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

La interfaz del registrador se inyecta perfectamente y todo funciona bien. SIN EMBARGO, si quiero inyectar mis propias clases en mi clase de Servicio utilizando el método constructor. P.ej:

<?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!');
    }
}

En este caso, nunca se llama al método constructor de mi rasgo, lo que significa que la propiedad $ logger de mi clase nunca se establece. Es cierto que no he usado muchos rasgos, así que mi conocimiento es un poco limitado, pero supongo que esto se debe a que mi clase ha anulado el método del constructor de mi rasgo. Esto es más o menos un espectáculo, ya que la mayoría de la base de código de Magento usa constructores para inyectar dependencias, descartando afectivamente su uso en rasgos.

La única solución real que puedo ver es usar ObjectManager directamente para inyectar sus dependencias de rasgos:

<?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;
    }
}

Descargo de responsabilidad: el uso de ObjectManager en Magento generalmente se desaconseja, pero por lo que puedo ver en este caso, es la única opción real. En mi ejemplo, si desea establecer una interfaz de registrador diferente en su clase, aún puede hacerlo inyectándola en su constructor y anulando la propiedad de clases $ logger.

Andrew Kett
fuente
En su clase, ha declarado 2 __construct, que es uno importado del rasgo y el otro en la clase misma. Sin embargo, no puede tener 2 métodos con el mismo nombre en una sola clase. Básicamente, en su caso, __constructel rasgo se anula __constructen la clase misma.
Rendy Eko Prastiyo