2

I am using admin_system_config_changed_section_[SECTION] to observe system config save action. Is there a way to detect if a field has changed or not?

3

The method isValueChanged() from vendor\magento\framework\App\Config\Value.php file will be able to find if the particular field value has been changed or not.

To use this, apply tag named backend_model in the module\etc\adminhtml\system.xml for which field you would like to detect.

system.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd">
    <system>
        <tab id="vendor" translate="label" sortOrder="10">
            <label>Vendor</label>
        </tab>
        <section id="module" translate="label" sortOrder="130" showInDefault="1" showInWebsite="1" showInStore="1">
            <class>separator-top</class>
            <label>General</label>
            <tab>vendor</tab>
            <resource>Vendor_Module::dimension_configuration</resource>
            <group id="general" translate="label" type="text" sortOrder="10" showInDefault="1" showInWebsite="0" showInStore="0">
                <label>General</label>                 
                <field id="dimension" translate="label" type="text" sortOrder="1" showInDefault="1" showInWebsite="0" showInStore="0">
                    <label>Dimension Text</label>
                    <comment>Dimension Text will display on the storefront.</comment>
                    <backend_model>Vendor\Module\Model\Config\Backend\Dimension</backend_model>
                </field>
            </group>
        </section>
    </system>
</config>

Dimension.php

namespace Vendor\Module\Model\Config\Backend;

class Dimension extends \Magento\Framework\App\Config\Value
{

    /**
     * @return $this
     */
    public function afterSave()
    { 
        if ($this->isValueChanged()) {

            //To get old value use function  $this->getOldValue();

            //To get value  use function  $this->getValue();


        }
        return parent::afterSave();
    }


}
2
  • 1
    Works like a charm. This should be the accepted answer. Thanks! – Daniel Kratohvil Feb 24 '20 at 16:20
  • Hi @DanielKratohvil, Can we save another config field's data inside this if loop? if ($this->isValueChanged()) { } Like this: $scope = $this->getData('scope'); $scopeId = $this->getData('scope_id'); if ($this->isValueChanged()) { $this->configWriter->save( self::TIMESTAMP_VALUE_FIELD, 0, $scope, $scopeId ); } return parent::afterSave(); – Octopus May 26 at 18:02
0

I didn't see a good solution so made one myself. I used a aroundSave() plugin on Magento\Config\Model\Config and took all the config settings before and after and checked the difference between these and added them in an array.

This is my code to achieve this:

Vendor\Module\etc\di.xml

<?xml version="1.0" ?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"
<type name="Magento\Config\Model\Config">
    <plugin name="name_of_plugin" 
      type="Vendor\Module\Plugin\Config\AroundSaveConfig"/>
</type>
</config>

Vendor\Module\Plugin\Config\AroundSaveConfig.php

<?php

namespace Vendor\Module\Plugin\Config;

class AroundSaveConfig
{

    /**
     * @var \Magento\Framework\App\Config\ScopeConfigInterface
     */
    private $scopeConfig;

    /**
     * AroundSaveConfig constructor.
     *
     * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
     */
    public function __construct(
        \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
    ) {
        $this->scopeConfig = $scopeConfig;
    }


    public function aroundSave(
        \Magento\Config\Model\Config $subject,
        callable $proceed
    ) {
        $section = $subject->getSection();
        $oldConfigs = $this->scopeConfig->getValue($section);
        //Proceed
        $returnValue = $proceed();

        $newConfigs = $this->scopeConfig->getValue($section);
        $changedValues = $this->checkDifference($oldConfigs, $newConfigs);

        $difference = $this->checkDifference($oldConfigs, $newConfigs);

        // Do whateever you want to do with the diff array which
        // contains both the old and new value of the array
    }


    public function checkDifference($array1, $array2)
    {
        foreach ($array1 as $key => $value) {
            if (is_array($value)) {
                if (!isset($array2[$key])) {
                    $difference[$key] = $value;
                } elseif (!is_array($array2[$key])) {
                    $difference[$key] = $value;
                } else {
                    $new_diff = $this->checkDifference($value, $array2[$key]);
                    if ($new_diff != false) {
                        $difference[$key] = $new_diff;
                    }
                }
            } elseif (!isset($array2[$key]) || $array2[$key] != $value) {
                $difference[$key] = [$value, $array2[$key]];
            }
        }
        return !isset($difference) ? 0 : $difference;
    }
}

This worked for my purposes where I only wanted the changed values. Hope this help you or someone else.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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