Take the 2-minute tour ×
Magento Stack Exchange is a question and answer site for users of the Magento e-Commerce platform. It's 100% free, no registration required.

When I think I got my head wrapped around the DI system from Magento 2 something comes up and un-wraps it.
I see in the core code different ways to access a helper.
For example in Magento\Catalog\Controller\Category::_initCategory there is this:

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

But in Magento\Catalog\Block\Category\View the helper is injected int he 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);
}

This lead me to think that the helpers should be accessed differently in controllers and blocks (and models) but then I found a controller where a helper is injected in the constructor Magento\Catalog\Controller\Adminhtml\Product\Action\Attribute.

Please clear the fog for me.
When should I use DI and when should I use objectManager? and why?
I've read this question: Instantiating Helpers in Magento 2 (November 2013). This is just a follow up question on that.

share|improve this question

2 Answers 2

up vote 3 down vote accepted

I would prefer DI where possible, as using the object manager is already a violation against the law of demeter. When using the object manager these dependencies are just hidden in the method logic.

share|improve this answer
    
Yep. I agree. I will use DI, but I'm curious to why this is done in the core? Maybe someone did not get to refactor the classes I mentioned, yet? –  Marius Jul 11 at 9:27
    
Afaik they're still refactoring a lot and hope they'll also touch these places, too. But also don't know about the priorities, which have to exist if they want to actually release at some point. So maybe some new features or other bad practices will be fixed first. –  Tobias Zander Jul 11 at 9:55

I don't know so much about the Magento implementation, but it looks like the ObjectManager is a Service Locator.

Generally using a Service Locator to access dependencies in an object is pretty bad, checkout out this article.

Explicitly defining your dependencies through a constructor is a much better approach. It aid's in unit testing and run time issues with services not being defined.

Injecting the Object Manager in to a class is basically injecting a Registry in to your class which has access to all of your applications services, which is obviously not right.

I use ZF2 a fair bit and generally define small factory classes for Services, Controllers and any class which require dependencies. These factory classes have access to the Service Locator and grab all services which the object depends on, and injects them through the constructor. Using a Service Locator in a Factory class is fine as it is mostly throw away code, something like this for example.

These factories are still easy to test.

IMO, Use constructor injection where ever possible. Again, I don't know too much about Magento's implementation and if it has the concept of Factories, from a quick look it does look like it supports them, but explicitly defining your classes and using a Service Locator to build them in Factory classes is a much cleaner approach.

This is from someone who has limited exposure to the above mentioned patters, so I would also like to hear other's thoughts / experiences on the matter!

More reading

share|improve this answer
    
Thanks for the nice explanation. My question was "Why are there 2 ways to access a helper in the core?" so this is a bit off-topic but it cleared some other doubts I had. :) Thanks. –  Marius Jul 11 at 9:26
    
I would probably say that it's just something that's just not refactored yet. Either that or it might be an ease-of-use thing. Requiring consumers to always inject all their dependencies in a Controller could be seen as counter-productive, especially when performing RAD. Giving consumers both ways to access dependencies would allow for the RAD approach but still allow for others to explicitly define their dependencies if they so wish. –  Aydin Hassan Jul 11 at 9:33

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.