DI y extensión de un bloque en Magento 2

15

Parece que estoy luchando por comprender la inyección de dependencia de Magento 2 con bloques, cada vez que intento extender un bloque que no es \ Magento \ Framework \ View \ Element \ Template termino con errores.

Quiero crear un bloque que extienda la clase de bloque muy básica de Magento \ Theme \ Block \ Html \ Header \ Logo : todo funciona bien hasta que intente la inyección de dependencia dentro del método de construcción:

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

Tan pronto como trato de inyectar mi clase auxiliar (o cualquier otra cosa, obtengo un seguimiento de la pila que comienza con el siguiente error:

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

Si agrego las mismas dependencias a mi __construcción, ya que el archivo que estoy extendiendo funciona, pero seguramente esa es una forma inversa de hacer las cosas, ya que el punto de herencia de clase es que absorbo todos los métodos y propiedades de los padres.

Creo que solo necesito una explicación básica de alguien para extenderme de las clases y usar DI con Magento 2. ¡Se agradece cualquier ayuda!

Adam Moss
fuente
"seguramente esa es una forma de hacer las cosas al revés", coincidió.
James

Respuestas:

19

La clase que intenta extender tiene este constructor:

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

así que necesitas hacer que tu constructor se vea así

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

Conclusión ...
En sus clases secundarias, debe especificar todos los parámetros del constructor de la clase principal más sus nuevos parámetros. No creo que el orden sea importante, y no sé cuál es la mejor práctica.
Luego, en el constructor, usted asigna sus nuevos objetos inyectados a los vars miembros y llama al constructor padre con el mismo número de parámetros que requiere.

Marius
fuente
2
Eso tiene sentido gracias por tu respuesta. Supongo que solo esperaba que fuera más elegante que eso.
Adam Moss
El orden de argumentos de @Marius debe coincidir con los argumentos del método de construcción de la clase principal __, sus argumentos personalizados deben pasar al final.
chirag dodia
@chiragdodia ¿Por qué? No lo creo. Todo lo que construí hasta ahora en M2 lo construí usando los argumentos de construcción personalizados agregados al azar. Y funcionó. la única restricción es que los argumentos con un valor predeterminado deberían ir al final.
Marius
@Marius sí, está funcionando en algunos casos, pero en mi caso cuando extendí \ Magento \ Catalog \ Block \ Product \ View no funciona, necesito hacer el mismo orden de argumentos que en el constructor principal y agregar argumentos personalizados por fin. Eche un vistazo a mi código aquí magento.stackexchange.com/questions/95697/…
chirag dodia
No
funcionó