1

I have a simple interface, PurgerInterface that has the methods needed to purge items from a cache backend (Varnish or Fastly). I have some custom configuration (standard system.xml stuff) that allows an admin to decide which backend they'd like to use (Varnish or Fastly).

I also have an Observer that listens to various events and will purge the appropriate caches. Here is the issue: I would like to inject, in my observer constructor, this purger interface like so:

public function __construct( CacheConfig $config, \Psr\Log\LoggerInterface $logger, PurgerInterface $purger) { ....

Now, the issue is that the concrete implementation of the PurgerInterface that I'd like injected is dependent on a configuration. If the Varnish backend is selected, I'd like VarnishPurger injected. If Fastly is selected, I'd like FastlyPurger.

Now, I'm familiar with other frameworks where you are able to dynamically bind items in the "service container" (I'm thinking Laravel here). Basically the logic / code controlling dependency injection can be interacted with, so when the container asks for a PurgerInterface I can run some code to check which concrete class I should return, and that is the class that is injected.

So, is this possible?

1 Answer 1

4

First, you need to create the factory that will be responsible for creating needed class base on configuration values. like

class Factory 
{
  ....
    public function create($data)
    {
        $className = $this->getClassFromConfiguration();
        $mapperInstance = $this->_objectManager->create($className, $data);

        if (false == $mapperInstance instanceof YourAdapterInterface) {
            throw new \Exception(
                'Object is not instance on YourAdapterInterface'
            );
        }
        return $mapperInstance;
    }
}

If you need to implements this for shared instance you should create Proxy.

class Proxy implements \Magento\Framework\ObjectManager\NoninterceptableInterface
{

    /**
     * @var \Magento\Config\Model\Config\Structure\Element\Group
     */
    protected $_subject;

    /**
     * @param Factory $factory
     */
    public function __construct($factory)
    {
        $this->factory = $objectManger;
    }

    /**
     * Retrieve subject
     *
     * @return YourAdapterInterface
     */
    protected function _getSubject()
    {
        if (!$this->_subject) {
            $this->_subject = $this->factory->create()
        }
        return $this->_subject;
    }

    /**
     * Method from interface
     *
     */
    public function methodName()
    {
        return $this->_getSubject()->methodName();
    }

    ... implementation of all methods from the interface by pattern

}

and use this class as the preference for interface

4
  • Thank you very much for the reply @KAndy! Can you explain the idea / logic / code behind the proxy as it related to a "shared instance"? The factory idea is a good one and ultimately if this is the way to go about creating my instance based on configuration then that's fine, although I had hoped that Magento 2 would allow for a way to do this via some built in DI feature. Commented Jul 5, 2016 at 13:45
  • @KevinMitchell Proxy is referring as a lazy loading pattern for the dependencies, so you can load the dependency but is like switched off until you use the first time in the main class. Shared refers to singleton pattern so can't be instantiated more than once. Commented Sep 14, 2016 at 10:20
  • as per magento we should not use _objectManager , with out _objectManager can we achieve this? if yes please how to Commented Oct 27, 2017 at 10:10
  • @PradeepKumar Factories are an exception to this rule. devdocs.magento.com/guides/v2.3/extension-dev-guide/… Also Proxies are generated code. You shouldn't create your own proxy unless you have a reason to do so. devdocs.magento.com/guides/v2.3/extension-dev-guide/…
    – Martin J.
    Commented May 7, 2020 at 20:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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