cancel
Showing results for 
Search instead for 
Did you mean: 

Configurable Dependency Injection

SOLVED

Configurable Dependency Injection

Hello!

 

I am porting one of my custom modules from Magento 1 to Magento 2 and I would like to do it in the right way.

The module is a communication utility in which you can configure in Backend the message encapsulation (JSON, XML, ...), the communication channel (REST Call, files on FTP, queues ...) and have your message correctly delivered to the right endpoint.


Magento 1 Scenario
There was a master module and  a lot of "plugins" (Format XML, Format JSON, Channel FTP, Channel AMQP...).

In the master module there were some Abstract Classes for Format, Channel, etc. and some "Factory" Methods in Data helper to instantiate the correct classes. For example there was a getFormatHelper that, depending on the actual configuration, instantiated the XML or the JSON helper with something like:

  public function getFormatHelper(){
    $store_id=Mage::app()->getStore()->getId();
    $format=Mage::getStoreConfig("dataqueue/general/format", $store_id);
    $class=Mage::getConfig()->getNode("global/dataqueue/format/".$format."/class");
    try{
      return Mage::helper($class);
    }
    catch(Exception $e){
      return null;
    }
  }

Each plugin had a custom config section such global/dataqueue/format/json in example below:

<global>
        <models>
            <dataqueue>
                <class>MyCompany_DataQueue_Model</class>
            </dataqueue>
        </models>
        <helpers>
          <dataqueue>
            <class>MyCompany_DataQueue_Helper</class>
          </dataqueue>
        </helpers>
        <dataqueue>
          <format>
            <json>
              <label>JSON</label>
              <class>dataqueue/format_json</class>
            </json>
          </format>
         </dataqueue>
    </global>
</config>

The system.xml of master module read all these sections to populate the configuration select boxes.

 

Magento 2

I read a lot of online articles on Dependency Injection and I like it very much. But I wasn't able to find out how to translate in Magento 2 a Dependecy Injection that actually depends on the parameters that are setted in backend.
Is there any Magento 2 new feature that could help me in this case?

 

Many thanks in advance for any suggestion you'll give me.

 

Regards,
Manuel

1 ACCEPTED SOLUTION

Accepted Solutions

Re: Configurable Dependency Injection

Dependency injection is not a replacement for configuration settings via Admin panel. Dependency injection is for programmers to wire things together. I will think a bit more, but I think you will still need separate configuration settings if it is for Admin's to think about.

 

I would however suggest thinking about whether the setting is for a merchant or a solution partner (maybe "Marketer" vs "developer" is a better distinction). Is it a setting you want to commit into "git" and push through any staging environments for example?  We are doing similar reviews ourselves, to work out which settings should be in Admin for a Marketing to fiddle with, versus which are for a developer.

 

For example, in the area of themes, picking the currently active theme is a Marketing decision. The list of what themes are available is a developer decision. We are looking at more clearly separating "data" from "code", where in this case the active theme is a "data" decision (and would be stored as a value in the database), where as the list of themes available is "code" (files on disk etc).

 

I mention this as you can do "code" level configuration in the di.xml file. E.g. a solution partner can write a simple module to change a configuration setting in your di.xml file (if you wrote an extension). You can have a separate configuration file if that is more natural, but the di.xml file can be used for this as well. But if a marketer/merchant should be able to change the value like in production, then that becomes "data" and should be in the Admin panel - and is unlikely to be set via the di.xml file for that reason.

 

I hope this makes sense!

View solution in original post

2 REPLIES 2

Re: Configurable Dependency Injection

Dependency injection is not a replacement for configuration settings via Admin panel. Dependency injection is for programmers to wire things together. I will think a bit more, but I think you will still need separate configuration settings if it is for Admin's to think about.

 

I would however suggest thinking about whether the setting is for a merchant or a solution partner (maybe "Marketer" vs "developer" is a better distinction). Is it a setting you want to commit into "git" and push through any staging environments for example?  We are doing similar reviews ourselves, to work out which settings should be in Admin for a Marketing to fiddle with, versus which are for a developer.

 

For example, in the area of themes, picking the currently active theme is a Marketing decision. The list of what themes are available is a developer decision. We are looking at more clearly separating "data" from "code", where in this case the active theme is a "data" decision (and would be stored as a value in the database), where as the list of themes available is "code" (files on disk etc).

 

I mention this as you can do "code" level configuration in the di.xml file. E.g. a solution partner can write a simple module to change a configuration setting in your di.xml file (if you wrote an extension). You can have a separate configuration file if that is more natural, but the di.xml file can be used for this as well. But if a marketer/merchant should be able to change the value like in production, then that becomes "data" and should be in the Admin panel - and is unlikely to be set via the di.xml file for that reason.

 

I hope this makes sense!

Re: Configurable Dependency Injection

Thanks Alan!

Actually, an additional xml file may be the best solution.
Meanwhile I managed to implement what I needed with a custom Factory class. It is still "imperfect" since I have not learnt yet how to make custom xml configurations but it works: when I need to format data I inject the factory that chooses the right class depending on actual backend configuration.

<?php
/**
 * Copyright © 2016 Filoblu S.r.l. All rights reserved.
 */ 
namespace FiloBlu\Esb\Helper\Format;

/**
 * Factory class to build Format Helper depending on System Configuration (JSON or XML)
 */

class FormatFactory{
    /**
     * @var array
     */
    protected $_pluginConfiguration;

    /**
     * @var \Magento\Framework\App\Config\ScopeConfigInterface
     */
    protected $_scopeConfig;

    /**
     * @var \Magento\Framework\ObjectManagerInterface
     */
    protected $_objectManager;

    /**
     * Constructor
     *
     * @param \Magento\Framework\ObjectManagerInterface $objectManager
     * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig   
     */
    public function __construct(
        \Magento\Framework\ObjectManagerInterface $objectManager,
        \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
    )
    {
        $this->_objectManager = $objectManager;
        $this->_scopeConfig = $scopeConfig;
        $this->_pluginConfiguration = array(
            "xml" => "\FiloBlu\Esb\Helper\Format\Xml",
            "json" => "\FiloBlu\Esb\Helper\Format\Json",
        );
    }

    /**
    * Creates Format Helper instance depending on System Configuration (JSON or XML)
    */    
    public function create(){
        $configuredFormat=$this->_scopeConfig->getValue(
            'esb/general/format', 
            \Magento\Store\Model\ScopeInterface::SCOPE_STORE
        );
        if(array_key_exists($configuredFormat, $this->_pluginConfiguration)){
            $configuredClass=$this->_pluginConfiguration[$configuredFormat];
            $formatHelper = $this->_objectManager->create($configuredClass);
            if (false == $formatHelper instanceof FormatInterface) {
                throw new \Exception(
                    'Object is not instance of FormatInterface'
                );
            }
        }else{
            throw new \Exception("Cannot find format class for $configurableFormat");
        }        
        return $formatHelper;
    }
}