by Kevin Schroeder | 8:23 am

A few days ago I wrote a blog post on how configuration works in Magento.  While it was fairly comprehensive it missed out on one very important piece of information; how the configuration file merges.  It is this merging that gives Magento the power it does for being extensible and so configurable.  All over the place you will see code like

1
Mage::getStoreConfig('node/somechild');

You will see this or something similar EVERYWHERE.  The reason why this is powerful is  because it allows for multiple different configuration files to be loaded all at once, merged into one giant configuration array and then access any node defined in any file from any place in your application.  And, perhaps, once you see now it works any mysticism you may have towards Magento configuration may be slightly de-mysticism-fied.

Let’s start with something basic. The Magento base configuration object is based off of Varien_Simplexml_Element, which, itself, extends the PHP SimpleXML class.  The problem is that the Simplexml class does not merge XML files very well (at all).  So the core Magento devs created a mechanism that allows XML files to be merged.  To see how this works let’s take a look at what this looks like on a small example.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$config = new Varien_Simplexml_Element(
'<config>
  <child1>text</child1>
</config>'
);
 
$config2 = new Varien_Simplexml_Element(
'<config>
  <child2>text</child2>
</config>'
);
 
$config->extend($config2);
 
echo $config->asNiceXml();

When we run this code we get the output

1
2
3
4
<config>
   <child1>text</child1>
   <child2>text</child2>
</config>

See that? By calling the extend() method on the $config object, the two objects were both appended to the base <config> node.

How about multiple different nodes?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$config = new Varien_Simplexml_Element(
'<config>
  <base1>
    <child1>text</child1>
  </base1>
</config>'
);
 
$config2 = new Varien_Simplexml_Element(
'<config>
  <base2>
    <child2>text</child2>
  </base2>
</config>'
);
 
$config->extend($config2);
 
echo $config->asNiceXml();

This code renders

1
2
3
4
5
6
7
8
<config>
   <base1>
      <child1>text</child1>
   </base1>
   <base2>
      <child2>text</child2>
   </base2>
</config>

How this is really cool is when you start dealing with multiple nested nodes.

1
2
3
4
5
6
7
8
9
10
11
$config = new Varien_Simplexml_Element(
'<config><base1><child1>text1</child1></base1></config>'
);
 
$config2 = new Varien_Simplexml_Element(
'<config><base1><child2>text2</child2></base1></config>'
);
 
$config->extend($config2);
 
echo $config->asNiceXml();

This renders

1
2
3
4
5
6
<config>
   <base1>
      <child1>text1</child1>
      <child2>text2</child2>
   </base1>
</config>

Then if you wanted to retrieve all of the children you could use the Mage_Core_Model_Config_Base class (which you would normally get by Mage::getConfig() or, preferably, Mage::getStoreConfig()).

1
2
3
4
5
6
7
$base = new Mage_Core_Model_Config_Base($config);
 
$node = $base->getNode('base1');
 
foreach ($node->children() as $name => $child) {
    echo sprintf("%s: %s\n", $name, $child);
}

So why is this cool? Because it allows you to hook your module into multiple other modules or system components without modifying the config files of said components. Could you have simpler syntax to register an observer? Sure. But it would require either a less consistent interface or explicitly loading config files any time a module needs to be used.

So when you are writing a node under global/events/controller_action_predispatch/observers/my_custom_observer what you are doing is working within the merging system in way that puts your information in a predictable location. For events, they are looking for children under global/events/{$event}/observers. By having your name unique there you are figuratively making it part of an associative array where the key is only used to maintain uniqueness. The merging system does not create arrays of like-named nodes; the last node with a given name will always win. That is why, if you are injecting your data into a previously defined node, such as events, you need to give it a unique node name.

Hopefully these little examples can help you make sense of how you can work with the config system in Magento.

Comments

william decamp

is it normal for Varien_Simplexml_Element::asNiceXml to be called 298 times in one execution of /catalog/category/view for 1870ms? This is New Relic is telling me on my installation. Seems excessive to me unless I don’t have a configuration correct.

May 26.2015 | 05:25 pm

    Kevin Schroeder

    That is actually quite expected which is why caching the configuration object is so important.

    May 27.2015 | 06:17 am

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.