Categories


Archives


Recent Posts


Categories


Instantiating and Injecting Helpers in Magento 2

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!

With the loss of the Mage class in Magento 2, you may be wondering how to instantiate a helper object. That is, the following will product an error in Magento 2

$helper = Mage::helper('core/data');

Similar to the object manager, Magento 2 has a helper factory which lets you instantiate helper methods. In fact, you use the object manager to instantiate the helper factory. So, in Magento 2 you accomplish the above with

$object_manager = MagentoCoreModelObjectManager::getInstance();
$helper_factory = $object_manager->get('MagentoCoreModelFactoryHelper');
$helper         = $helper_factory->get('MagentoCoreHelperData');

If you think that looks like more work than is necessary — you’re right. Fortunately, for day-to-day Magento programming, there’s a better way: Magento 2’s new automatic dependency injection system.

Ahhh! Fancy meaningless buzz words!! Here’s what that means.

Let’s pretend you’re working on a new model in Magento 2.

<?php
namespace PulsestormHelloinjectionModel;
class Something extends MagentoObject
{
    public function translateString($string)
    {
        return Mage::helper('core')->__($string);
    }
}

The above code would fail in Magento 2, because there’s no Mage class. Instead, you’d write something like this

namespace PulsestormHelloinjectionModel;
class Something extends MagentoObject
{
    public function translateString($string)
    {
        return $this->_coreHelper->__($string);
    }
}    

You’re expected to keep helper classes as object properties (_coreHelper above). However, the above will also give us an error, because we never assigned a helper to _coreHelper. We could do something like this

<?php
namespace PulsestormHelloinjectionModel;
class Something extends MagentoObject
{
    protected $_coreHelper;
    public function __construct()
    {
        $object_manager     = MagentoCoreModelObjectManager::getInstance();
        $helper_factory     = $object_manager->get('MagentoCoreModelFactoryHelper');
        $this->_coreHelper  = $helper_factory->get('MagentoCoreHelperData');        
    }

    public function translateString($string)
    {
        return $this->_coreHelper->__($string);
    }
}   

However, as mentioned, that’s a lot of code to write for a simple helper assignment. Also, a developer might do something like this

public function __construct()
{
    $object_manager     = MagentoCoreModelObjectManager::getInstance();
    $this->_coreHelper  = $object_manager->get('MagentoCoreHelperData');
}

In the above example we’ve skipped the helper factory and just instantiated the MagentoCoreHelperData class as a cached object via the object manager. This will get us mostly the same behavior, but there may be consequences to not letting the helper factory know about the object. Also, it doesn’t look like our other code, and having different styles all over the codebase can and will confuse people. If anything’s going to confuse people, it should be our business logic, and not a simple helper assignment.

This is where Magento 2’s auto dependency injection comes in.

<?php
namespace PulsestormHelloinjectionModel;
class Something extends MagentoObject
{
    protected $_coreHelper;

    /**
    * @param MagentoCoreHelperData $coreData
    */        
    public function __construct(MagentoCoreHelperData $coreData)
    {
        $this->_coreHelper = $coreData;            
    }

    public function translateString($string)
    {
        return $this->_coreHelper->__($string);
    }
}  

In above code, we’ve replaced our constructor with a much simpler one. This constructor has a single paramater ($coreData), which the constructor then assigns to our _coreHelper property.

Nothing special so far — except that this code will run as is. That is, we could instantiate this class with

$o = $object_manager->get('PulsestormHelloinjectionModel');
echo $o->translateString("Hello");

and PHP wouldn’t complain — even though we never pass in a helper object. If that made no sense, don’t worry, you’re not crazy. That’s the magic of Magento 2’s new automatic dependency injection.

Take a look at the constructor.

/**
* @param MagentoCoreHelperData $coreData
*/        
public function __construct(MagentoCoreHelperData $coreData)
{
    $this->_coreHelper = $coreData;            
}

In Magento 2, if you include a parameter with a type hint

public function __construct(MagentoCoreHelperData $coreData)

The object manager will automatically instantiate the helper class for you, and pass it in as a constructor parameter. In other words, the helper is automatically injected into your class’s constructor.

If the using PHPDoc comments as part of your program pattern is new to you, this may look a little crazy. However, this practice is becoming increasingly common in the PHP world — both Symfony 2 and Doctrine 2 use PHPDoc annotations in a programmatically significant way. It’s also an old pattern too, many of the early java Design by Contract implementations leveraged Javadoc for similar purposes.

Note: The original version of this quickie assumed Magento was using the PHPDoc function for type hinting information. This is not the case.

It’ll be interesting to see how Magento’s auto-injection plays out as time goes on, but I’m generally encouraged by it. This is the rare bit of Magento meta-programming that hides some of Magento’s native complexity from end-user-programmers, and that can only be a good thing.

Copyright © Alan Storm 1975 – 2019 All Rights Reserved

Originally Posted: 8th November 2013