Magento 2 Tutorials

Magento 2 and Dependency Injection

mage static method prefix

In Magento 2, the MageDeath Star” is no more. It got replaced in favor of the Dependency Injection pattern. Let’s take a look at what Dependency Injection is and how it affects Magento 2.

What is Dependency Injection?

Dependency Injection is part of SOLID and makes sure all dependents are decoupled points which combined, form a system. Every single dependent should ideally only be responsible for one exact task. All other tasks a dependent requires to function, called the dependencies, are injected into the dependent.

To illustrate the problem it solves, consider the following Magento 1.X core code snippet.

public function getMail()
{
if (is_null($this->_mail)) {
$this->_mail = new Zend_Mail('utf-8');
}
return $this->_mail;
}

In the above method from the Mage_Core_Model_Email_Template class, we can see that this class is hard-coded dependent of Zend_Mail. If Zend_Mail needs to be replaced with a different mail library, core files will have to be modified.

Mage_Core_Model_Email_Template could have had a constructor parameter or method which injects the dependency, but it would have to be a subclass of Zend_Mail or a class which features the same interface to ensure compatibility. A snippet like this is a very logical reason why implementing dependency injection in Magento 1.X in later stages was a no-go.

The code base got too fragmented and complex, that resolving all dependency-problems and implementing dependency injection, required a complete new mindset. One in which dependency injection lies at the foundation of the architecture and is not something you can use.

Inversion of Control

An often natural pattern which occurs when implementing dependency injection, is inversion of control. This is nothing more than that instead of directly controlling target components, there is one (or more) point of entry for delegating control.

This comes naturally, because with dependency injection you do not want to satisfy all dependencies over and over. You want a centralized system which either has predefined instances of dependents or can generate them on the fly.

In Magento 2

So how does all of this come together in Magento 2? Writing complete documentation of how you can use dependency injection is far beyond the purpose of the article; we will gloss over the implementation.

Continuing with our previous example of the hard-coded Zend_Mail in Magento 1.X, let’s take a look at how it is solved in Magento 2. The following code comes from the User model and shows that instead of calling something like Mage::getModel(‘core/email_template’), the code call for sending out emails has been completely revised.

public function sendPasswordResetConfirmationEmail()
{
// Set all required params and send emails
/** @var \Magento\Framework\Mail\TransportInterface $transport */
$transport = $this->_transportBuilder->setTemplateIdentifier(
$this->_config->getValue(self::XML_PATH_FORGOT_EMAIL_TEMPLATE)
)->setTemplateOptions(
array('area' => \Magento\Framework\App\Area::AREA_FRONTEND, 'store' => 0)
)->setTemplateVars(
array('user' => $this, 'store' => $this->_storeManager->getStore(0))
)->setFrom(
$this->_config->getValue(self::XML_PATH_FORGOT_EMAIL_IDENTITY)
)->addTo(
$this->getEmail(),
$this->getName()
)->getTransport();

$transport->sendMessage();
return $this;
}

It might look complex at first, but all this does is making TransportBuilder responsible for delivering a transport object with an interface of TransportInterface. This ensures that no matter what the underlying implementation is, you will always get back an instance on which you can call the sendMessage method.

Looking at TransportBuilder, all it does is setting the prerequisites for sending out an email. It’s sole responsibility is preparing all the underlying components (template rendering, configuring transporter, wrapping the e-mail et cetera). The result is that all components are interchangeable and individually testable.

The Object Manager and di.xml

Looking at any class involved in TransportBuilder its process or even the TransportBuilder itself, reveals a large constructor with often at least three parameters referring to other dependencies. This is how Magento 2 (and many other systems) its dependency injection system works.

By inspecting (reflection) a class constructor its type-hinted arguments, the Magento 2 Object Manager will automatically inject those dependencies. This does indeed mean that most if not all class instantiations will have to go via the object manager eventually. It will be an oddity when you have to use the new keyword in Magento 2.

For example, when you want the “old” Mage::getModel(‘sales/order_item’)->getCollection(), you now request the instance from the object manager which will automatically give you a dependency-injected instance based on the type hints of the Order\Item model:

$this->_objectManager->create(
'Magento\Sales\Model\Order\Item'
)->getCollection()

Because type hints can also refer to interfaces, the new Magento 2 di.xml should specify on application (/app/etc/di.xml), module (/app/code/$module/etc/di.xml) or module-area (/app/code/$module/etc/$areaCode/di.xml) level what the preferences are for specific type-hinted arguments. Examples and proper configuration of the di.xml file can be found in the documentation.

One of the advantages of being able to specify specific implementations of interfaces is that you can also roll your own implementations in favor of Magento’s . Partially they seem to be able to be replacing the Magento 1.X class rewrites.

Final words

Whether you like it or not, dependency injection is coming to a future Magento 2 installation near you.

It solves the problem of tightly coupled code and enforces separation of concerns. Though we understand Magento its desire to have an enterprise code base, we would have loved a bit more syntactic sugar by – for example – leveraging facades for commonly used factories and non-injectables.

However, hopefully third-party developers will embrace the dependency injection methodology in Magento 2 and refrain from hacking around the object manager because they think their model its constructor looks silly.

Further reading

Subscribe Newsletter

Subscribe to get latest Magento news

40% Off for 4 Months on Magento Hosting + 30 Free Migration