Question

This is driving me crazy! The general/region/state_required data from system->configuration cannot be retrieved by Mage::getStoreConfig() function. In the database, this value is presented, and data persistence works OK as well, i.e. changing the value in the CMS will take the change the database. The following is a abstraction from system.xml of Magento default Directory module.

<general>
        <groups>
            <country>
                <fields>
                    <optional_zip_countries translate="label">
                        <label>Postal Code is Optional for the following countries</label>
                        <frontend_type>multiselect</frontend_type>
                        <sort_order>3</sort_order>
                        <source_model>adminhtml/system_config_source_country</source_model>
                        <show_in_default>1</show_in_default>
                        <show_in_website>0</show_in_website>
                        <show_in_store>0</show_in_store>
                        <can_be_empty>1</can_be_empty>
                    </optional_zip_countries>
                </fields>
            </country>
            <region translate="label">
                <label>States Options</label>
                <frontend_type>text</frontend_type>
                <sort_order>4</sort_order>
                <show_in_default>1</show_in_default>
                <show_in_website>0</show_in_website>
                <show_in_store>0</show_in_store>
                <fields>
                    <state_required translate="label">
                        <label>State is required for</label>
                        <frontend_type>multiselect</frontend_type>
                        <source_model>adminhtml/system_config_source_country</source_model>
                        <sort_order>1</sort_order>
                        <show_in_default>1</show_in_default>
                        <show_in_website>0</show_in_website>
                        <show_in_store>0</show_in_store>
                    </state_required>
                    <display_all translate="label">
                        <label>Display not required State</label>
                        <frontend_type>select</frontend_type>
                        <source_model>adminhtml/system_config_source_yesno</source_model>
                        <sort_order>8</sort_order>
                        <show_in_default>1</show_in_default>
                        <show_in_website>0</show_in_website>
                        <show_in_store>0</show_in_store>
                    </display_all>
                </fields>
            </region>
        </groups>
    </general>

In fact, general/region/display_all returns null as well while it has a non-empty value. This is really weird, I have no idea about it now, can anyone please help?!

--Update--

Is it possible that this value is being overridden somewhere? Like some code hardcode this value to be null, it overrides the value in the db.

I tried a couple of methods suggested below, unfortunately they don't solve the problem here. Any more input from people?

Was it helpful?

Solution

There is an article series by Alan Storm that covers the internals of Mage::getStoreConfig() extensively:

  1. http://alanstorm.com/magento_config_tutorial
  2. http://alanstorm.com/magento_config_declared_modules_tutorial
  3. http://alanstorm.com/magento_loading_config_variables

In short, the value can come from:

  1. default, config/websites and config/stores nodes in any XML file in app/etc (might even be in app/etc/modules, but it's highly unlikely)
  2. default, config/websites and config/stores nodes in any module's config.xml
  3. core_config_data table
  4. default, config/websites and config/stores nodes in app/etc/local.xml

Configuration is loaded in this order, overriding existing values in each step (i.e. local.xml has highest priority)

It is also possible to set configuration values at runtime in the Config model without having them saved anywhere. Searching for Mage::getConfig() in your local code pool might help you finding it.

OTHER TIPS

I've came across this exact issue and have figured out how to solve it.

When core config data is loaded from the database inside app/code/core/Mage/Core/Model/Resource/Config.php on line 90

    // load all configuration records from database, which are not inherited
    $select = $read->select()
        ->from($this->getMainTable(), array('scope', 'scope_id', 'path', 'value'));
    if (!is_null($condition)) {
        $select->where($condition);
    }
    $rowset = $read->fetchAll($select);


    // set default config values from database
    foreach ($rowset as $r) {
        if ($r['scope'] !== 'default') {
            continue;
        }
        $value = str_replace($substFrom, $substTo, $r['value']);
        $xmlConfig->setNode('default/' . $r['path'], $value);
    }

all data is fetched from core_config_data and is saved in the xml structure. The data is loaded in same order as the config_id, so what happened was, there was an empty default value set and somewhere toward end of the table like this: enter image description here

notice id 2203. The path is set to general and the value is NULL!

When Magento processes id 2203 inside lib/Varien/Simplexml/Config.php on line 548:

public function setNode($path, $value, $overwrite=true)
{
    $xml = $this->_xml->setNode($path, $value, $overwrite);
    return $this;
}

The NULL default path value wipes the values inside its xml object.

How did this happen?

Well, if we look deeper inside Magento and check how the core_config_data table was created we see that

CREATE TABLE `{$installer->getTable('core_config_data')}` (
  `config_id` int(10) unsigned NOT NULL auto_increment,
  `scope` enum('default','websites','stores','config') NOT NULL default 'default',
  `scope_id` int(11) NOT NULL default '0',
  `path` varchar(255) NOT NULL default 'general',
  `value` text NOT NULL,
  PRIMARY KEY  (`config_id`),
  UNIQUE KEY `config_scope` (`scope`,`scope_id`,`path`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

so by default Magento sets the default path to default, default scope_id to 0, but notice the value is not supposed to be NULL. So how did Magento save a NULL value?

Simple, someone/something did something like this Mage::getConfig()->saveConfig('general'); Try it and see for yourself; it'll work and Magento will save a NULL value in the table. If you're interested in understanding why it works, take a look inside app/code/core/Mage/Core/Model/Config.php line 1535:

public function saveConfig($path, $value, $scope = 'default', $scopeId = 0)
{
    $resource = $this->getResourceModel();
    $resource->saveConfig(rtrim($path, '/'), $value, $scope, $scopeId);

    return $this;
}

and inside app/code/core/Mage/Core/Model/Resource/Config.php on line 184:

    public function saveConfig($path, $value, $scope, $scopeId)
{
    $writeAdapter = $this->_getWriteAdapter();
    $select = $writeAdapter->select()
        ->from($this->getMainTable())
        ->where('path = ?', $path)
        ->where('scope = ?', $scope)
        ->where('scope_id = ?', $scopeId);
    $row = $writeAdapter->fetchRow($select);

    $newData = array(
        'scope'     => $scope,
        'scope_id'  => $scopeId,
        'path'      => $path,
        'value'     => $value
    );

    if ($row) {
        $whereCondition = array($this->getIdFieldName() . '=?' => $row[$this->getIdFieldName()]);
        $writeAdapter->update($this->getMainTable(), $newData, $whereCondition);
    } else {
        $writeAdapter->insert($this->getMainTable(), $newData);
    }
    return $this;
}

Also see https://stackoverflow.com/questions/18908309/mysql-column-set-to-not-null-but-still-allowing-null-values

TL;DR; Solution Run this sql query:

SELECT * FROM magento.core_config_data WHERE value IS NULL;

and delete the row where path === default and value IS NULL(see my screenshot for reference).

DELETE FROM core_config_data WHERE scope = 'default' AND scope_id = 0 AND path = 'general' AND value IS NULL;

You can query the config after explicitly setting the store using either of the following:

$config = Mage::getStoreConfig('inchoo/inchoo_group/inchoo_input', Mage::app()->getStore());

or

Mage::app()->setCurrentStore(0);

$config = Mage::getStoreConfig('general/region/state_required');

You could also explicitly reload the configuration and then load the values using

Mage::app()->getConfig()->reinit();

Mage::getStoreConfig('inchoo/inchoo_group/inchoo_input', Mage::app()->getStore());

Licensed under: CC-BY-SA with attribution
Not affiliated with magento.stackexchange
scroll top