Categories: Magento 2 Tutorials

Magento 2 and Dependency Injection

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 reasona 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

Magenticians

View Comments

  • Thanks for the great article. Did I get this wrong or you can get any object with Object Manager regardless of what's in di.xml for that module?

    • Yes, you can create any object. di.xml need mostly for interface preferences and modularity. Also OM simplify things like pre configured objects and lazy initialization.

    • Yes. di.xml is just a configuration file. Do note that by using the object manager you are forcing a dependency on the object manager and retrieved dependencies are not directly visible. Direct use of it is not recommended.

      • Yeah, that's why I think it is not needed at all because it encourages bad programming practices.

  • Dependency Injection is not part of SOLID. Dependency Inversion is. They are different concepts.

  • Great!.. any idea how to translate this code?
    $customer = Mage::getModel("customer/customer");
    $customer->setFirstName("New Name");
    $customer->save();

Share
Published by
Magenticians

Recent Posts

Building Employee Trust and Dedication – A Complete Guide

In the highly competitive modern workplace, trust, and employee loyalty are crucial factors for long-term… Read More

3 months ago

12 Winning Strategies for Small Businesses Marketing

In the ever-evolving world of small business developing and implementing effective marketing strategies is critical to… Read More

3 months ago

Top 10 App Development Companies in Dubai 2024

With one of the highest internet penetration rates, the UAE has set out to revolutionize… Read More

3 months ago

Transforming Industries: How Amazons GPT44X is Revolutionizing AI Technology

Artificial Intelligence (AI) has been continually evolving, leading to remarkable advancements in various industries. Among… Read More

8 months ago

Top Magento 2 Extensions for 2023

Extensions, extensions and lots of extensions. We all love extensions, don’t we? After all, extensions… Read More

11 months ago

Unleashing the Power of Software Testing: Cooperating with a Testing Firm

Software quality is crucial to a firm's success across industries in the quickly changing digital… Read More

11 months ago