Instance Magento 2 Helper

11

Quand je pense avoir enroulé ma tête autour du système DI de Magento 2, quelque chose arrive et le déballe.
Je vois dans le code principal différentes façons d'accéder à un assistant.
Par exemple, Magento\Catalog\Controller\Category::_initCategoryil y a ceci:

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

Mais dans Magento\Catalog\Block\Category\Viewl'aide est injecté dans le constructeur

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

Cela m'a amené à penser que les assistants devraient être accessibles différemment dans les contrôleurs et les blocs (et les modèles), mais j'ai ensuite trouvé un contrôleur où une aide est injectée dans le constructeur Magento\Catalog\Controller\Adminhtml\Product\Action\Attribute.

S'il vous plaît, nettoyez le brouillard pour moi.
Quand dois-je utiliser DI et quand dois-je utiliser objectManager? et pourquoi?
J'ai lu cette question: Instanciation des aides dans Magento 2 . Ce n'est qu'une question complémentaire à ce sujet.

Marius
la source

Réponses:

10

Je préférerais DI si possible, car l'utilisation du gestionnaire d'objets est déjà une violation de la loi de Demeter. Lorsque vous utilisez le gestionnaire d'objets, ces dépendances sont simplement masquées dans la logique de la méthode.

Tobias
la source
Oui. Je suis d'accord. Je vais utiliser DI, mais je suis curieux de savoir pourquoi cela se fait dans le noyau? Peut-être que quelqu'un n'a pas encore refactorisé les cours que j'ai mentionnés?
Marius
Afaik, ils refactorisent encore beaucoup et espérons qu'ils toucheront également ces endroits aussi. Mais je ne sais pas non plus sur les priorités, qui doivent exister si elles veulent réellement sortir à un moment donné. Alors peut-être que de nouvelles fonctionnalités ou d'autres mauvaises pratiques seront corrigées en premier.
Tobias
Que se passe-t-il si vous disposez d'une classe de 10 fonctions et qu'UNE SEULE fonction nécessite un modèle spécifique? Ne serait-il pas redondant (de la vue des performances) de charger le modèle via l'injection de constructeur pour chacune des 10 fonctions alors que nous pourrions le charger en utilisant le gestionnaire d'objets uniquement à l'intérieur d'une seule fonction?
JohnyFree
6

Je ne connais pas tellement l'implémentation de Magento, mais il semble que ce ObjectManagersoit un localisateur de service .

Généralement, l'utilisation d'un localisateur de service pour accéder aux dépendances dans un objet est assez mauvaise, consultez cet article .

Définir explicitement vos dépendances via un constructeur est une bien meilleure approche. Il facilite les tests unitaires et les problèmes d'exécution avec les services non définis.

Injecter le gestionnaire d'objets dans une classe revient à injecter un registre dans votre classe qui a accès à tous vos services d'applications, ce qui n'est évidemment pas correct.

J'utilise assez bien ZF2 et je définis généralement de petites classes d'usine pour les services, les contrôleurs et toute classe nécessitant des dépendances. Ces classes d'usine ont accès au localisateur de services et récupèrent tous les services dont l'objet dépend, et les injectent via le constructeur. L'utilisation d'un localisateur de service dans une classe Factory est très bien car il s'agit principalement de code jeté, quelque chose comme ça par exemple.

Ces usines sont toujours faciles à tester .

OMI, utilisez l'injection de constructeur dans la mesure du possible. Encore une fois, je ne sais pas trop sur l'implémentation de Magento et s'il a le concept des usines, à première vue, il semble qu'il les prend en charge, mais définir explicitement vos classes et utiliser un localisateur de service pour les construire dans les classes d'usine est une approche beaucoup plus propre.

Cela vient de quelqu'un qui a une exposition limitée aux patters mentionnés ci-dessus, donc j'aimerais également entendre les pensées / expériences des autres sur la question!

Plus de lecture

Aydin Hassan
la source
Merci pour la belle explication. Ma question était "Pourquoi y a-t-il 2 façons d'accéder à un assistant dans le noyau?" c'est donc un peu hors sujet, mais cela a dissipé certains autres doutes que j'avais. :) Merci.
Marius
Je dirais probablement que c'est juste quelque chose qui n'est pas encore refactorisé. Soit cela, soit cela pourrait être une chose facile à utiliser. Obliger les consommateurs à toujours injecter toutes leurs dépendances dans un contrôleur pourrait être considéré comme contre-productif, en particulier lors de l'exécution de RAD. Donner aux consommateurs les deux façons d'accéder aux dépendances permettrait l'approche RAD mais permettrait aux autres de définir explicitement leurs dépendances s'ils le souhaitent.
Aydin Hassan
5

Une autre façon d'utiliser l'assistant (dans les modèles) est:

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

J'espère que c'est utile si vous ne le saviez pas déjà.

rbncha
la source
ceci est en quelque sorte similaire à l'utilisation du gestionnaire d'objets. Pas sûr que ce soit la meilleure idée.
Marius
1
La méthode ci-dessus ne concerne que les modèles pour autant que je sache. Le gestionnaire d'objets est utilisé dans les contrôleurs, les blocs, les modèles, etc.
rbncha
1
Ce n'est pas dans le même stade que le code car il n'y a pas de dépendances de code sur les modèles. Les modèles ne sont que des consommateurs et ne polluent aucun client avec une encapsulation cassée.
demonkoryu
Je ne sais pas ce que demonkoryu essaie de dire. Mais la meilleure façon d'appeler l'aide d'un module est la suivante. C'est Magento. Comme on dit, chaque code de bloc / section est destiné à être appelé / modifiable sans toucher au noyau. Donc, tout est interrelié ou a des dépendances.
rbncha
2

Bien que ce soit une vieille question, je ne sais pas si Marius a obtenu sa réponse. Je crois que Marius peut y répondre mieux. Je voudrais y répondre brièvement. Pourquoi Magento 2 suggère d'utiliser DI au lieu de Helper?

  • Rendre l'isolation dans les tests unitaires possible / facile
  • Définition explicite des dépendances d'une classe
  • Faciliter une bonne conception (principe de responsabilité unique (PRS) par exemple)
  • L'utilisation de DI dans votre module réduit le risque de bogues d'incompatibilité lorsque Magento modifie l'implémentation sous-jacente de ces interfaces. Il s'agit d'un concept important à comprendre pour les développeurs d'extensions.

Pourquoi le noyau M2 pourrait ne pas utiliser DI dans certains cas?

  • Nombre de cours décroissant
  • Ne pas créer d'interfaces inutiles
  • Aucun risque de bugs d'incompatibilité

Bien que le module de catalogue principal ait été utilisé comme assistant, il a largement utilisé DI. Dans mes recherches, j'ai trouvé que Magento 2 utilisait peu de fonctions dans les fichiers d'assistance du catalogue principal qui ne conviennent pas aux contrats de service.

Si vous devez utiliser explicitement une classe définie par Magento (telle que \ Magento \ Catalog \ Model \ Product), rendez la dépendance implicite explicite en fonction de l'implémentation concrète au lieu de l'interface du contrat de service.

Sans aucun doute, le développeur d'extensions devrait utiliser DI au lieu de Magento1 comme Helper. Lors de la mise en œuvre selon les directives de Magento 2, les retombées sont limitées. Lors de la rupture des recommandations, des problèmes surviennent.

Agilox
la source
Ouais, j'ai ma réponse en attendant. Mais merci d'avoir pris le temps de répondre. Ces informations sont précieuses pour les personnes qui recherchent ceci en ligne.
Marius