Instancia de ayuda de Magento 2

11

Cuando creo que obtuve mi cabeza envuelta alrededor del sistema DI de Magento 2, algo surge y lo desenvuelve.
Veo en el código central diferentes formas de acceder a un ayudante.
Por ejemplo, Magento\Catalog\Controller\Category::_initCategoryahí está esto:

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

Pero en Magento\Catalog\Block\Category\Viewel ayudante se inyecta en el constructor

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

Esto me llevó a pensar que se debería acceder a los ayudantes de manera diferente en los controladores y bloques (y modelos), pero luego encontré un controlador donde se inyecta un ayudante en el constructor Magento\Catalog\Controller\Adminhtml\Product\Action\Attribute.

Por favor, despeja la niebla para mí.
¿Cuándo debo usar DI y cuándo debo usar objectManager? ¿y por qué?
He leído esta pregunta: Instanciando ayudantes en Magento 2 . Esta es solo una pregunta de seguimiento sobre eso.

Marius
fuente

Respuestas:

10

Preferiría DI siempre que sea posible, ya que usar el administrador de objetos ya es una violación de la ley de demeter. Cuando se usa el administrador de objetos, estas dependencias se ocultan en la lógica del método.

Tobias
fuente
Sí. Estoy de acuerdo. Usaré DI, pero tengo curiosidad por saber por qué esto se hace en el núcleo. ¿Quizás alguien todavía no pudo refactorizar las clases que mencioné?
Marius
Afaik todavía están refactorizando mucho y esperamos que también toquen estos lugares también. Pero tampoco conozca las prioridades, que deben existir si quieren publicar en algún momento. Entonces, tal vez algunas características nuevas u otras malas prácticas se solucionen primero.
Tobias
¿Qué sucede si tiene una clase de 10 funciones y SOLO 1 función requiere un modelo específico? ¿No sería redundante (desde la vista de rendimiento) cargar el modelo a través de la inyección del constructor para cada una de las 10 funciones, mientras que podríamos cargarlo usando el administrador de objetos solo dentro de una sola función?
JohnyFree
6

No sé mucho sobre la implementación de Magento, pero parece que ObjectManageres un Localizador de servicios .

En general, usar un Localizador de servicios para acceder a dependencias en un objeto es bastante malo, consulte este artículo .

Definir explícitamente sus dependencias a través de un constructor es un enfoque mucho mejor. Ayuda en pruebas unitarias y problemas de tiempo de ejecución con servicios no definidos.

Inyectar el Administrador de objetos en una clase es básicamente inyectar un Registro en su clase que tiene acceso a todos sus servicios de aplicaciones, lo que obviamente no es correcto.

Utilizo ZF2 bastante y generalmente defino clases pequeñas de fábrica para servicios, controladores y cualquier clase que requiera dependencias. Estas clases de fábrica tienen acceso al Localizador de servicios y toman todos los servicios de los que depende el objeto, y los inyecta a través del constructor. El uso de un Localizador de servicios en una clase de Fábrica está bien, ya que se trata principalmente de código desechable, algo como esto, por ejemplo.

Estas fábricas aún son fáciles de probar .

OMI, use la inyección del constructor siempre que sea posible. Una vez más, no sé demasiado sobre la implementación de Magento y si tiene el concepto de Fábricas, a simple vista parece que las admite, pero definir explícitamente sus clases y usar un Localizador de servicios para construirlas en las clases de Fábrica es Un enfoque mucho más limpio.

Esto es de alguien que tiene una exposición limitada a los patrones mencionados anteriormente, por lo que también me gustaría escuchar los pensamientos / experiencias de otros sobre el asunto.

Más lectura

Aydin Hassan
fuente
Gracias por la buena explicación. Mi pregunta fue "¿Por qué hay 2 formas de acceder a un asistente en el núcleo?" así que esto está un poco fuera de tema pero despejó algunas otras dudas que tenía. :) Gracias.
Marius
Probablemente diría que es algo que todavía no se ha refactorizado. O eso o podría ser una cosa fácil de usar. Requerir que los consumidores siempre inyecten todas sus dependencias en un Controlador podría verse como contraproducente, especialmente cuando se realiza RAD. Dar a los consumidores ambas formas de acceder a las dependencias permitiría el enfoque RAD, pero aún permitiría que otros definan explícitamente sus dependencias si así lo desean.
Aydin Hassan
5

Otra forma de usar helper (en plantillas) es:

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

Espero que sea útil si aún no lo sabías.

rbncha
fuente
esto es de alguna manera similar al uso del administrador de objetos. No estoy seguro de que sea la mejor idea.
Marius
1
El método anterior es solo para plantillas hasta donde yo sé. El administrador de objetos se usa en controladores, bloques, modelos, etc.
rbncha
1
No está en el mismo estadio que el código porque no hay dependencias de código en las plantillas. Las plantillas son solo consumidores y no contaminan a ningún cliente con una encapsulación rota.
demonkoryu
No sé qué demonkoryu está tratando de decir. Pero la mejor manera de llamar al ayudante de cualquier módulo es esta. Este es Magento. Como dicen, cada código de bloque / sección está destinado a ser invocable / modificable sin tocar el núcleo. Entonces, todo está interrelacionado o tiene dependencias.
rbncha
2

Aunque es una pregunta antigua, no estoy seguro de si Marius obtuvo su respuesta. Creo que Marius puede responderlo mejor. Me gustaría responder en breve. ¿Por qué Magento 2 sugiere usar DI en lugar de ayuda?

  • Hacer posible el aislamiento en las pruebas unitarias / fácil
  • Definición explícita de dependencias de una clase
  • Facilitar un buen diseño (principio de responsabilidad única (SRP) por ejemplo)
  • El uso de DI en su módulo reduce el riesgo de errores de incompatibilidad cuando Magento cambia la implementación subyacente de esas interfaces. Este es un concepto importante para los desarrolladores de extensiones.

¿Por qué el núcleo M2 podría no usar DI en algunos casos?

  • Número decreciente de clases
  • No crear interfaces innecesarias
  • Sin riesgo de errores de incompatibilidad

Aunque el módulo de catálogo Core se ha usado como ayudante, se ha usado DI ampliamente. En mi investigación, descubrí que Magento 2 usaba pocas funciones en los archivos auxiliares del Catálogo principal que no son adecuados para los contratos de servicio.

Si debe usar explícitamente una clase definida por Magento (como \ Magento \ Catalog \ Model \ Product), haga explícita la dependencia implícita dependiendo de la implementación concreta en lugar de la interfaz del contrato de servicio.

Sin lugar a dudas, el desarrollador de extensiones debe usar DI en lugar de Magento1 como Helper. Cuando se implementa de acuerdo con las pautas de Magento 2, las consecuencias son limitadas. Cuando se rompen las recomendaciones, ocurren problemas.

Agilox
fuente
Sí, recibí mi respuesta mientras tanto. Pero gracias por tomarse el tiempo de responder. Esta es información valiosa para las personas que buscan esto en línea.
Marius