Magento – Get system config option inside source model of another option

configurationmagento2store-idstore-viewsystem-config

In my custom module I have two custom option in the system configuration. Values of the second option depend on the value of the first option. My problem is that inside the source model of the second option I don't know how to retrieve the value of the first option.

Options

Here's how the options are defined:

View in Magento admin panel

\app\code\Company\Images\etc\adminhtml\system.xml:

<field id="custom_folder" translate="label" sortOrder="10" type="text" showInDefault="1" showInWebsite="1" showInStore="1">
    <label>Custom folder</label>
</field>
<field id="list_of_icons" translate="label" sortOrder="20" type="select" showInDefault="1" showInWebsite="1" showInStore="1">
    <label>List of icons</label>
    <source_model>Company\Images\Model\System\Config\Source\Icons\Custom</source_model>
</field>

And here's a short description of what these options actually do:

  • first option: custom_folder – folder path, user can define a path to custom folder which stores images (icons)

  • second option: list_of_icons – dropdown list of all icons inside the folder which is defined in the first option.

From this list the user can select an icon which will be displayed on the frontend. This dropdown list will be used in multiple places in the system configuration pages of my module (to add icons to multiple elements of the frontend) but it will always show the list of icons from the folder selected in the custom_folder option.

Source model

For the second option list_of_icons I've created a source model. It should list all icons which exist in the folder specified by user in the first option (custom_folder). Here's the code of the source model:

\app\code\Company\Images\Model\System\Config\Source\Icons\Custom.php:

<?php
namespace Company\Images\Model\System\Config\Source\Icons;

class Custom
{
    /**
     * @var \Magento\Store\Model\StoreManagerInterface
     */
    protected $_storeManager;

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

    public function __construct(
        \Magento\Store\Model\StoreManagerInterface $storeManager,
        \Magento\Framework\App\Config\ScopeConfigInterface $configScopeConfigInterface

    ) {
        $this->_storeManager = $storeManager;
        $this->_scopeConfigInterface = $configScopeConfigInterface;
    }

    public function toOptionArray()
    {
        // Get current store view ID
        $storeId = $this->_storeManager->getStore()->getId();

        // Get value of the first option in the current store view
        $folderPath = $this->_scopeConfigInterface->getValue(
            'images/icons/custom_folder',
            'store',
            $storeId
        );

        $options = [];
        // Here we need to list all image files from the specified folder.
        // It's not relevant to my question, so this part of code can be omitted.
        // ...

        return $options;
    }
}

What I tried to do

So inside that source model in the toOptionArray() method I need to retrieve the value of the first option (the folder path). Of course I need the value from the current store view:

enter image description here

I tried to do it like this:

// Get current store view ID
$storeId = $this->_storeManager->getStore()->getId();

// Get value of the first option in the current store view
$folderPath = $this->_scopeConfigInterface->getValue(
    'images/icons/custom_folder',
    'store',
    $storeId
);

but this line:

$storeId = $this->_storeManager->getStore()->getId();

always returns the ID of the Default Config, instead of the current store view ID.

So my code always retrieves the value of the option from the Default Config, no matter in which store view I am at the moment on the system configuration page in admin panel.

I need the value from the current store view, because each store view can have different folder path configured by user, so in each store view the list of icons (presented in the second option) can be completely different.

The problem

So, to sum up, the problem is the following:

  • How to correctly retrieve the value of the first option when I'm inside the source model of the second option?

And this problem comes down to:

  • How I can get the ID of the current store view inside the code of the source model?

If I have the ID of the current store view I will be able to easily retrieve the value of the first option.

Best Answer

The way you approach to make the custom configuration fields dependant will be achieved through the steps suggested by @Piyush and @Lez(Using source models with request library).

However, this approach has a drawback - which forces the merchant to save, once the first configuration field value is entered. Only then, you can use that value for the second field, which results in bad user(merchant) experience. Definitely, not a recommended one.

An alternative approach will be using javascript with ajax loader - the way Magento fetches the regions for the respective countries. Debugging that further, end me up in the

vendor/magento/module-config/view/adminhtml/templates/system/config/js.phtml

This template file is loaded in the configuration pages and the script in the template is responsible for fetching the regions for the respective country when modified. Line no: 125

reloadRegionField : function(event)
    {
        this.reload = true;
        var countryElement = Event.element(event);
        if (countryElement && countryElement.id) {
            var regionElement  = $(countryElement.id.replace(/country_id/, 'region_id'));
            if (regionElement) {
                this.regionElement = regionElement;
                if (countryElement.value.length) {
                    var url = this.regionsUrl+'parent/'+countryElement.value;
                    this.loader.load(url, {}, this.refreshRegionField.bind(this));
                } else {
                    this.clearRegionField(this.regionElement.disabled);
                }
            }
        }
    }

If you have a look at this method, it uses the country value and fetches the respective regions using the loader. This method gets binded to the country field(refer bindCountryRegionRelation() in the same class).

So you can override the same template, add your own class with respective methods(event handler) to reload the second field. Finally, bind that event handler to the first field.

Summing up, it is good to follow the same approach to fetch the image files(using loader) when "custom_folder" input value gets changed. Also, this will fetch only the current store value.

I hope this heads you in the right direction.

Related Topic