Since Magento base store (Luma store) is set to demonstration only, we need to learn how to set configuration data in Magento 2 to use for our own purposes.

In case you have multiple stores to work with and changing default configurations aren’t enough to satisfy your purpose, this article will show you how to set configuration data by scope to match your customization.

Manage configuration by scope

Set configuration data in Magento 2

Magento saves all admin settings in core_config_data table in your Magento database. There you can get values by its path, a string which indicates the path to and a variable name.

Set config data in Magento 2

In order to set data for this table, we can use save() function which is located in \Magento\Framework\App\Config\Storage\WriteInterface.

interface WriterInterface
{
   /**
    * Delete config value from storage
    *
    * @param   string $path
    * @param   string $scope
    * @param   int $scopeId
    * @return void
    */
   public function delete($path, $scope = ScopeConfigInterface::SCOPE_TYPE_DEFAULT, $scopeId = 0);

   /**
    * Save config value to storage
    *
    * @param string $path
    * @param string $value
    * @param string $scope
    * @param int $scopeId
    * @return void
    */
   public function save($path, $value, $scope = ScopeConfigInterface::SCOPE_TYPE_DEFAULT, $scopeId = 0);
}

How to use this save() function? You only need to play these in your class:

A constructor that calls to writerInterface.

public function __construct(
   \Magento\Framework\App\Config\Storage\WriterInterface $configWriter

){
   $this->_configWriter = $configWriter;
}

Then drop:

$this->_configWriter->save($path, $value, $scope = ScopeConfigInterface::SCOPE_TYPE_DEFAULT, $scopeId = 0);

anywhere in which you want to save config inside your class.

In which:

  • $path is the config path that you want to set your new value.
  • $value is your new custom value.
  • $scope can be either ‘store’, group, ‘website’ which can be found in app/code/Magento/Store/Model/ScopeInterface.php or global scope ‘default’ that is defined in /Magento/Framework/App/ScopeInterface.php.
  • $scopeId can be 0 if you set as default or you can find your scope_id in Magento store, store_group, store_website table in database.

Get configuration data in Magento 2

We have learned how to set configuration data, but what if we want to retrieve config data to use?

We can do this by using getValue() function from Magento\Framework\App\Config\ScopeConfigInterface.

interface ScopeConfigInterface
{
   /**
    * Default scope type
    */
   const SCOPE_TYPE_DEFAULT = 'default';

   /**
    * Retrieve config value by path and scope.
    *
    * @param string $path The path through the tree of configuration values, e.g., 'general/store_information/name'
    * @param string $scopeType The scope to use to determine config value, e.g., 'store' or 'default'
    * @param null|string $scopeCode
    * @return mixed
    */
   public function getValue($path, $scopeType = ScopeConfigInterface::SCOPE_TYPE_DEFAULT, $scopeCode = null);

   /**
    * Retrieve config flag by path and scope
    *
    * @param string $path The path through the tree of configuration values, e.g., 'general/store_information/name'
    * @param string $scopeType The scope to use to determine config value, e.g., 'store' or 'default'
    * @param null|string $scopeCode
    * @return bool
    */
   public function isSetFlag($path, $scopeType = ScopeConfigInterface::SCOPE_TYPE_DEFAULT, $scopeCode = null);
}

The specific functions can be found in Magento\Framework\App\Config:

public function getValue(
   $path = null,
   $scope = ScopeConfigInterface::SCOPE_TYPE_DEFAULT,
   $scopeCode = null
) {
   if ($scope === 'store') {
       $scope = 'stores';
   } elseif ($scope === 'website') {
       $scope = 'websites';
   }
   $configPath = $scope;
   if ($scope !== 'default') {
       if (is_numeric($scopeCode) || $scopeCode === null) {
           $scopeCode = $this->scopeCodeResolver->resolve($scope, $scopeCode);
       } elseif ($scopeCode instanceof \Magento\Framework\App\ScopeInterface) {
           $scopeCode = $scopeCode->getCode();
       }
       if ($scopeCode) {
           $configPath .= '/' . $scopeCode;
       }
   }
   if ($path) {
       $configPath .= '/' . $path;
   }
   return $this->get('system', $configPath);
}

Preparation

Same as setConfig in order to use this function, we just need to call ScopeConfigInterface in construct function, then call it anywhere as below.

public function __construct(
   \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
)
{
   $this->_scopeConfig = $scopeConfig;
}

And then use getValue() function:

$this->_scopeConfig->getValue($path, $scopeType = ScopeConfigInterface::SCOPE_TYPE_DEFAULT, $scopeCode = null);
  • $path is the config path that you want to set your new value.
  • $scopeType: The scope using to determine config value. It can be either ‘store’, group, ‘website’ which can be found in app/code/Magento/Store/Model/ScopeInterface.php or global scope ‘default’ that is defined in /Magento/Framework/App/ScopeInterface.php.
  • $scopeCode can be null or if you’re using another scope than 'default', you can find its scopeCode in matching table. Eg: ‘store’ scope has scopeId as found in store table.

Using the above code, you can easily get store config value by scope in Magento.

NOTE:

One thing to keep in mind when setting config in the frontend is that you have to clear cache in order to retrieve new value. To do this automatically after saving new config or prepare to get config data, make sure to insert these lines of code.

Add cacheTypeList to your constructor:

protected $cacheTypeList;
public function __construct( 
\Magento\Framework\App\Cache\TypeListInterface $cacheTypeList 
){
    $this->cacheTypeList = $cacheTypeList;
}

Clear cache after saving or prepare to read by adding these to your code.

$this->cacheTypeList
->cleanType(\Magento\Framework\App\Cache\Type\Config::TYPE_IDENTIFIER);
$this->cacheTypeList
->cleanType(\Magento\PageCache\Model\Cache\Type::TYPE_IDENTIFIER);

Manage configuration data by default

Magento has provided us with a variety of configuration options for our store. Not only it is easy to access but also user-friendly, you just need to go to the admin menu, select Stores > Settings > Configuration.

Manage configuration data in Magento Back-end
Manage configuration data in Magento Back-end

As we can see, there is a multitude of configuration options for our store which we can set as we want to.

However, what if we want to change it depends on the particular circumstances. For example, I want to change product visibility based on store type. These custom options are not provided by Magento store configuration but have to be changed programmatically.

Manage configuration data by backend model

All Backend Model classes (indirectly or directly) inherit from the class Magento\Framework\App\Config\Value. This class enables us to use many interesting methods that facilitate writing our own Backend Model including, but not limited to getValue(), isValueChanged() or getOldValue().

Firstly, we need to create our own configuration field in etc/adminhtml/system.xml with below code:

<group id="test_backend" 
            translate="label" 
            type="text" 
            sortOrder="1" 
            showInDefault="1" 
            showInWebsite="1" 
            showInStore="1">
                <label>Backend model test</label>
                <field id="custom_backend_model" 
                    translate="label" 
                    type="text" 
                    sortOrder="1" 
                    showInDefault="1" 
                    showInWebsite="1" 
                    showInStore="1">
                    <label>Custom backend model</label>
                    <backend_model>Magenest\Demo\Model\Config\Backend\Custom</backend_model>
                </field>
            </group>

Next, we will create a backend model which uses beforeSave() and afterSave() method. These methods are inherited from Magento class Magento\Framework\App\Config\Value.

class Custom extends \Magento\Framework\App\Config\Value

Backend model class must extends from Magento Value class.

In this example, we use ValueFactory in order to save the new value.

Make sure to include it in the constructor function, along with other required value for our class.

public function __construct( 
        \Magento\Framework\App\Config\ValueFactory $configValueFactory,
      ){
          $this->_configValueFactory = $configValueFactory;
        }
public function beforeSave()
    {
        $label = $this->getData('field_config/label');

        if ($this->getValue() == '') {
            throw new \Magento\Framework\Exception\ValidatorException(__($label . ' is required.'));
        } else if (!is_numeric($this->getValue())) {
            throw new \Magento\Framework\Exception\ValidatorException(__($label . ' is not a number.'));
        } else if ($this->getValue() < 0) {
            throw new \Magento\Framework\Exception\ValidatorException(__($label . ' is less than 0.'));
        }

        $this->setValue(intval($this->getValue()));

        parent::beforeSave();
    }

This function will check the requirement for our custom field and throw an exception if the input value didn’t meet requirements.

Now we will create a function for saving the new configuration as well as overwrite old value if it was created. Also, we add a little tag as ‘Mark as new value’ after the new config data just saved.

public function afterSave()
    {
        $value = $this->getValue() . '_Mark as new value';

        try {
            $this->_configValueFactory->create()->load(
                self::CUSTOM_OPTION_STRING_PATH,
                'path'
            )->setValue(
                $value
            )->setPath(
                self::CUSTOM_OPTION_STRING_PATH
            )->save();
        } catch (\Exception $e) {
            throw new \Exception(__('We can\'t save new option.'));
        }

        return parent::afterSave();
    }

As you can see, the Backend Model gives us control over all elements that are being updated in our module’s configuration and ensures that we can avoid future complications.

Conclusion

Magento provided multiple ways to get/set store configuration. By setting and/or getting data programmatically, you can work on multiple store shops. Moreover, to retrieve data and set it as in particular cases programmatically way is the right way to do it.