Categories


Archives


Recent Posts


Categories


Magento 2: Injecting Interfaces

astorm

Frustrated by Magento? Then you’ll love Commerce Bug, the must have debugging extension for anyone using Magento. Whether you’re just starting out or you’re a seasoned pro, Commerce Bug will save you and your team hours everyday. Grab a copy and start working with Magento instead of against it.

Updated for Magento 2! No Frills Magento Layout is the only Magento front end book you'll ever need. Get your copy today!

Pop quiz: You’ve got your head wrapped around Magento 2’s dependency injection. You’re taking a stroll through the code base, and you see this constructor.

#File: lib/Magento/PubSub/Event/QueueHandler.php
public function __construct(MagentoPubSubEventQueueReaderInterface $eventQueue,
    MagentoPubSubJobQueueWriterInterface $jobQueue,
    MagentoPubSubJobFactoryInterface $jobFactory,
    MagentoPubSubSubscriptionCollectionInterface $subscriptionSet
) {
    $this->_eventQueue = $eventQueue;
    $this->_jobQueue = $jobQueue;
    $this->_jobFactory = $jobFactory;
    $this->_subscriptionSet = $subscriptionSet;
}

Since you know about Magento’s automatic dependency injection, you know the _eventQueue property should contain an object that’s an instance of the MagentoPubSubJobQueueWriterInterface class.

Except MagentoPubSubJobQueueWriterInterface isn’t a class. It’s a PHP programatic interface

#File: lib/Magento/PubSub/Event/QueueReaderInterface.php
namespace MagentoPubSubEvent;

interface QueueReaderInterface
{
    //...
}

What do you do now, hotshot?

Interfaces and Dependency Injection

Don’t worry, Magento’s automatic dependency injection is not a homunculus who blows up buses or instantiates objects from interfaces. Instead, if you use an interface as a type hint in a Magento object’s constructor, the system will search for that interface’s preferred class.

A module developer (the core team, you, etc.) specifies these preferences in a module’s di.xml file. In the above example, the interface’s full name is MagentoPubSubEventQueueReaderInterface. If we look in the following file

#File: app/code/Magento/Webhook/etc/di.xml
<preference for="MagentoPubSubEventQueueReaderInterface" 
            type="MagentoWebhookModelEventQueueReader" />                

We can see the authors of the Magento_Webhook module have specified a preference for the MagentoPubSubEventQueueReaderInterface interface as the class MagentoWebhookModelEventQueueReader.

What does this mean? When the automatic dependency injection system sees

MagentoPubSubEventQueueReaderInterface
public function __construct(MagentoPubSubEventQueueReaderInterface $eventQueue, ...

it will instantiate the object in $eventQueue with the MagentoWebhookModelEventQueueReader class.

While this all is a little confusing the first time you encounter it, I like the direction. Tying the auto-injected classes to a specific interface (i.e. a core PHP language feature) seems like an win, and will help prevent configuration swapping of classes (i.e “class rewrites” in Magento 1) from breaking the original class’s implicit contract.

In less nerdy terms, it would be impossible for someone to rewrite the class MagentoWebhookModelEventQueueReader without implementing all the methods in the QueueReaderInterface interface. In Magento 1 the same rewrite could (accidentally) omit some necessary QueueReader method that would only be discovered when/if the method was used at runtime, maybe days after the initial deployment. This “interfaces in dependency injection” feature brings Magento 2 developers some compile-time-like checking that our Java and C# friends take for granted.

Copyright © Alan Storm 1975 – 2019 All Rights Reserved

Originally Posted: 26th November 2013