Magento 2 Helper instance

11

Когда я думаю, что обернул голову вокруг системы DI из Magento 2, что-то появляется и разворачивается.
Я вижу в основном коде разные способы доступа к помощнику.
Например, Magento\Catalog\Controller\Category::_initCategoryтам есть это:

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

Но в Magento\Catalog\Block\Category\Viewпомощник вводится конструктор

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

Это привело меня к мысли, что к помощникам следует обращаться по-разному в контроллерах и блоках (и моделях), но затем я нашел контроллер, в который в конструктор вводится помощник Magento\Catalog\Controller\Adminhtml\Product\Action\Attribute.

Пожалуйста, очистите туман для меня.
Когда я должен использовать DI и когда я должен использовать objectManager? и почему?
Я прочитал этот вопрос: Создание помощников в Magento 2 . Это просто дополнительный вопрос по этому вопросу.

Мариус
источник

Ответы:

10

Я бы предпочел DI, где это возможно, так как использование менеджера объектов уже является нарушением закона Деметры. При использовании диспетчера объектов эти зависимости просто скрываются в логике метода.

Тобиас
источник
Ага. Согласен. Я буду использовать DI, но мне интересно, почему это делается в основном? Может, кто-то еще не смог провести рефакторинг классов, о которых я говорил?
Мариус
Afaik, они все еще много занимаются рефакторингом и надеются, что они тоже коснутся этих мест. Но также не знаю о приоритетах, которые должны существовать, если они хотят на самом деле выпустить в какой-то момент. Так что, возможно, некоторые новые функции или другие плохие практики будут исправлены в первую очередь.
Тобиас
Что если у вас класс из 10 функций и ТОЛЬКО 1 функция требует конкретной модели? Разве не было бы избыточно (с точки зрения производительности) загружать модель посредством внедрения в конструктор для каждой из 10 функций, в то время как мы могли бы загрузить ее с помощью диспетчера объектов только внутри одной функции?
JohnyFree
6

Я не так много знаю о реализации Magento, но похоже, что ObjectManagerэто Service Locator .

Как правило, использование Service Locator для доступа к зависимостям в объекте довольно плохо, ознакомьтесь с этой статьей .

Явное определение ваших зависимостей через конструктор - гораздо лучший подход. Это помогает в модульном тестировании и проблемах во время выполнения с сервисами, которые не определены.

Внедрение диспетчера объектов в класс - это внедрение реестра в ваш класс, который имеет доступ ко всем службам ваших приложений, что, очевидно, неправильно.

Я пользуюсь ZF2 и обычно определяю небольшие фабричные классы для Сервисов, Контроллеров и любого класса, который требует зависимостей. Эти фабричные классы имеют доступ к локатору службы и получают все службы, от которых зависит объект, и внедряют их через конструктор. Использование Service Locator в классе Factory хорошо, так как он в основном отбрасывает код, например, как этот .

Эти фабрики все еще легко проверить .

IMO, используйте конструктор инъекций там, где это возможно. Опять же, я не знаю слишком много о реализации Magento и, если она имеет концепцию Factories, с первого взгляда она выглядит так, как будто она их поддерживает, но явное определение ваших классов и использование Service Locator для их построения в классах Factory - это гораздо чище подход.

Это от кого-то, кто имеет ограниченное воздействие вышеупомянутых шаблонов, поэтому я также хотел бы услышать мысли / опыт других по этому вопросу!

Больше чтения

Айдын Хасан
источник
Спасибо за приятное объяснение. Мой вопрос был: «Почему в ядре есть 2 способа доступа к помощнику?» так что это немного не по теме, но это очистило некоторые другие сомнения, которые у меня были. :) Спасибо.
Мариус
Я бы, наверное, сказал, что это просто что-то, что еще не подверглось рефакторингу. Либо это, либо это может быть удобство использования. Требование потребителей всегда вводить все свои зависимости в Контроллере может считаться контрпродуктивным, особенно при выполнении RAD. Предоставление потребителям обоих способов доступа к зависимостям позволит использовать подход RAD, но все же позволит другим явно определять свои зависимости, если они того пожелают.
Айдын Хасан
5

Еще один способ использовать помощник (в шаблонах):

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

Я надеюсь, что это полезно, если вы еще не знали.

rbncha
источник
это как-то похоже на использование менеджера объектов. Не уверен, что это лучшая идея.
Мариус
1
Выше метод только для шаблонов, насколько я знаю. Диспетчер объектов используется в контроллерах, блоках, моделях и т. Д.
rbncha
1
Это не то же самое, что и код, потому что нет никаких кодовых зависимостей от шаблонов. Шаблоны являются только потребителями и не загрязняют клиентов нарушенной инкапсуляцией.
демонкорю
Я не знаю, что демонкорю пытается сказать. Но лучший способ вызвать помощника любого модуля - это. Это Magento. Как говорится, каждый код блока / секции предназначен для вызова / модификации без касания ядра. Итак, все взаимосвязано или имеет зависимости.
РБНЧА
2

Хотя это старый вопрос, я не уверен, что Мариус получил ответ. Я верю, что Мариус может ответить лучше. Я хотел бы ответить на это вкратце. Почему Magento 2 предлагает использовать DI вместо помощника?

  • Обеспечение изоляции в модульном тестировании возможно / просто
  • Явно определяющие зависимости класса
  • Содействие хорошему дизайну (например, принцип единой ответственности)
  • Использование DI в вашем модуле снижает риск ошибок несовместимости, когда Magento меняет базовую реализацию этих интерфейсов. Это важная концепция для разработчиков расширений.

Почему ядро ​​M2 может не использовать DI в некоторых случаях?

  • Уменьшение количества классов
  • Не создание ненужных интерфейсов
  • Нет риска несовместимости ошибок

Хотя модуль каталога Core использовался как вспомогательный, он широко использовал DI. В своем исследовании я обнаружил, что Magento 2 использует несколько функций в файлах вспомогательного каталога Core, которые не подходят для контрактов на обслуживание.

Если вам необходимо явно использовать Magento-определенный класс (например, \ Magento \ Catalogue \ Model \ Product), сделайте явную зависимость явной, полагаясь на конкретную реализацию вместо интерфейса контракта на обслуживание.

Несомненно, разработчик расширений должен использовать DI вместо Magento1, как Helper. При реализации в соответствии с рекомендациями Magento 2, последствия ограничены. При нарушении рекомендаций возникают проблемы.

Agilox
источник
Да, я получил ответ тем временем. Но спасибо, что нашли время ответить. Это ценная информация для людей, которые ищут это онлайн.
Мариус