We suppose you continue following our Magento certification-dedicated posts in our blog. This time we will tell you how Magento loads and manipulates configuration information.

Basically, Magento configuration is spread among dozens of .xml files. So this is a reasonable question – how does Magento operate all these files and find proper settings for each particular extension?

Let’s refresh some key points of the Magento structure

• Magento is a modular system, in which functionality is located in separate modules.

Later on we have a similar order of the class methods loading in both versions. In case of the Mage::run() all wrappers for processing configuration loading are located in Mage_Core_Model_App and refer to the Mage_Core_Model_Config methods. Calling Mage::app(), we immediately call Mage_Core_Model_Config::init(), which contains the process of configuration loading.

Finally, we come to Mage_Core_Model_Config, inherited from Mage_Core_Model_Config_Base and Varien_Simplexml_Config. At this stage the call method doesn’t matter, so let’s refer to Mage_Core_Model_Config:: init():

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

<?php

/**

* Initialization of core configuration

*

* @return Mage_Core_Model_Config

*/

publicfunctioninit($options=array())

{

// lets skip cache init and non-standard options stuff

$this->loadBase();

$cacheLoad=$this->loadModulesCache();

if($cacheLoad){

return$this;

}

$this->loadModules();

$this->loadDb();

$this->saveCache();

return$this;

}

Let’s analyze this method line by line.

$this->loadBase();

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

/**

* Load base system configuration (config.xml and local.xml files)

*

* @return Mage_Core_Model_Config

*/

publicfunctionloadBase()

{

$etcDir=$this->getOptions()->getEtcDir();

$files=glob($etcDir.DS.'*.xml');

$this->loadFile(current($files));

while($file=next($files)){

$merge=clone$this->_prototype;

$merge->loadFile($file);

$this->extend($merge);

}

if(in_array($etcDir.DS.'local.xml',$files)){

$this->_isLocalConfigLoaded=true;

}

return$this;

}

From the very beginning we define the absolute path to app/etc directory. Then we get a list of all .xml files from this catalog, read their content and merge into a single simpleXmlElement object. If local.xml file has been loaded (which generally means that Magento has already been installed), set flag $this->_isLocalConfigLoaded = true;. It will be used later to initialize store and load module setup scripts.

As far as this method doesn’t limit names and the amount of loaded files, we can add our custom .xml file into app/etc, if necessary. It can be helpful for specifying database connection data on a dev-server without the use of local.xml file, containing production-server information only.

1

2

3

4

5

<?php

$cacheLoad=$this->loadModulesCache();

if($cacheLoad){

return$this;

}

This piece of code speaks for itself. If the configuration cache is enabled and contains the required information, we load the entire config. We also replace the config that has already been loaded from app/etc with the one, loaded from the cache (Mage_Core_Model_Config:: loadCache()) and return back to Mage_Core_Model_App.

There is a reasonable question you might ask at this point: if the whole configuration can be loaded from cache, why haven’t developers made this verification the first step, before scanning app/etc directory?

The thing is that Magento cache can be stored not only as files in var/cache, but in apc, memcached and xcache as well. This particular step with files loading from app/etc allows to define the type and configuration of the cache storage used.

The next step is loading of the most extensive configuration part – modules configuration.

_getDeclaredModuleFiles(): At the beginning we scan app/etc/modules directory and collect the list of paths to all .xml files, indicating all modules in the system. We form an associative array with “base”, “mage” and “custom” keys. Only Mage_All.xml path goes to the “base” section. Modules from the Magento basic pack (located in app/code/core/Mage – code pool “core”) go to the «mage» section. «Custom» section collects the rest of modules. At the end we merge everything into a single array. Due to initial splitting into keys, data is stored in the following sequence: Mage_All.xml, modules with Mage namespace, all other modules.

If you haven’t figured out why Magento developers paid so much attention to Mage_All.xml file, it’s a high time for you to look inside of it. Mage_All.xml contains all information required for loading modules that are crucial for the proper system operation.

Next, information from the list of collected .xml files is loaded into Mage_Core_Model_Config_Base $unsortedConfig. Then we get the$moduleDepends array, based on <depends>, <active> flags and module name.

$this->_sortModuleDepends($moduleDepends): is necessary for checking dependencies of all existing modules. After the verification a new array is formed, where modules are arranged regarding their dependencies on one another.

At the end of _loadDeclaredModules() we create simpleXmlElement object again and merge it with the one that has been created earlier from app/etc/*.xml.

$resourceConfig contains config.mysql4.xml line. Thus, our next step will be loading configuration from config.mysql4.xml and config.mysql4.xml files. It is still not clear, what config.mysql4.xml was planned to be used for, but I really hope that further releases will exclude reference to this file or eventually it will prove to be needed.

First this method checks whether modules could be loaded from local code pool (pay attention at <disable_local_modules>false</disable_local_modules> in app/etc/local.xml). If only modules from community and core are permitted, Magento will change include_path() correspondingly.

1

2

3

4

5

6

7

8

9

10

<?php

if($disableLocalModules&&!defined('COMPILER_INCLUDE_PATH')){

set_include_path(

// excluded '/app/code/local'

BP.DS.'app'.DS.'code'.DS.'community'.PS.

BP.DS.'app'.DS.'code'.DS.'core'.PS.

BP.DS.'lib'.PS.

Mage::registry('original_include_path')

);

}

After this simple verification Magento ensures that we already have some config – simpleXmlElement (if we don’t – it creates it) and delete from the loaded list of modules ones that have keys <active>false</active> and <codePool>local</codePool>.

Then for each of remained modules config.xml and config.mysql4.xml files are loaded. Next, as you’ve most likely figured out by yourselves, the loaded .xml is added to the existing one. If the last loaded file already contains the older xpath, system will use the last value.

The $this->applyExtends(); call originally was a way to change (override) data in config with the help of a custom extension. But this functionality is not in use at the moment.

If someone has managed to read everything down to these lines, please, pay attention to the following piece of code:

As we see, developers took care of no module could modify system data from app/etc/local.xml (the default database connection, outer cache and proxy-servers settings).

Finally, we’ve approached $this->loadDb();

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

<?php

/**

* Load config data from DB

*

* @return Mage_Core_Model_Config

*/

publicfunctionloadDb()

{

if($this->_isLocalConfigLoaded&&Mage::isInstalled()){

Varien_Profiler::start('config/load-db');

$dbConf=$this->getResourceModel();

$dbConf->loadToXml($this);

Varien_Profiler::stop('config/load-db');

}

return$this;

}

This method uses resource Mage_Core_Model_Resource_Config model, related to core_config_data table. At this step we load data from core_config_data into our configuration:

1. We add data about websites (see core_website table)
2. We add data about stores for the existing websites (see core_store table)
3. We add data from core_config_data according to the scope
a. Create <default> block first
b. Then create <websites> block
c. And, finally – <stores>
d. Each iteration replaces data from more general area of the scope with more specific one (Do you remember these amazing «use default», «use website» and «configuration scope» in the backend?)
4. Self-configuration (if Magento meets data related to no longer existing website, these data will be deleted).

Pavel Novitsky is one of the few Magento Certified Developers Plus & Prestashop Certified Developer. He has 8 years of web-development experience. Pavel has developed Facebook Connect and Like free extension and for now it is installed on over 10 000 web stores. He gives lectures to other BelVG devs.

Pavel is married and has a son (whom he’s proud to call his major achievement). Pavel likes good music, philosophy books, detectives, adventure stories and “Winnie-the-Pooh” for relaxation.

In this article I am going to shed light on the classes and functions which work with Magento themes.

Main classes:

Mage_Core_Model_Layout

Mage_Core_Model_Layout_Update

Mage_Core_Model_Design

Mage_Core_Model_Design_Package

Mage_Core_Block_Templat

So, where does it all start?

Well, I am not going bother you with the detailed description of how Magento is launched from the outset. Instead, I would like to begin with Controllers, since they launch the assembling of a shop theme . (more…)

Thank you for your helpful articles, anyway there is something that is not so clear to me.

You say “As far as this method – loadBase() – doesn’t limit names and the amount of loaded files, we can add our custom .xml file into app/etc, if necessary. It can be helpful for specifying database connection data on a dev-server without the use of local.xml file, containing production-server information only.”

But this doesn’t seem to work, because, as you write after “As we see, developers took care of no module could modify system data from app/etc/local.xml (the default database connection, outer cache and proxy-servers settings).”

Infact even if the loadBase() loads every xml file in the app/etc dir, the loadModules() reloads the “local.xml” making our custom xml files useless.

To my mind, adding development database configuration without changing local.xml is more theoretical than practical question. Something like rewriting store configuration would be more suitable example.

Anyways, the “local.xml reloading” does not prevent from adding new database connection.

Here is the example – a part of the production local.xml:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

<config>

<global>

<resources>

<default_setup>

<connection>

<host><![CDATA[localhost]]></host>

<username><![CDATA[production_dbuser]]></username>

<password><![CDATA[production_password]]></password>

<dbname><![CDATA[production_magento_db]]></dbname>

<initStatements><![CDATA[SET NAMES utf8]]></initStatements>

<model><![CDATA[mysql4]]></model>

<type><![CDATA[pdo_mysql]]></type>

<pdoType><![CDATA[]]></pdoType>

<active>1</active>

</connection>

</default_setup>

</resources>

</global>

</config>

And here is app/etc/mydev.xml:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

<?xml version="1.0"?>

<config>

<global>

<resources>

<dev_setup>

<connection>

<host><![CDATA[localhost]]></host>

<username><![CDATA[dev_dbuser]]></username>

<password><![CDATA[dev_password]]></password>

<dbname><![CDATA[dev_magento_db]]></dbname>

<initStatements><![CDATA[SET NAMES utf8]]></initStatements>

<model><![CDATA[mysql4]]></model>

<type><![CDATA[pdo_mysql]]></type>

<pdoType><![CDATA[]]></pdoType>

<active>1</active>

</connection>

</dev_setup>

<default_write>

<connection>

<use>dev_setup</use>

</connection>

</default_write>

<default_read>

<connection>

<use>dev_setup</use>

</connection>

</default_read>

<core_setup>

<connection>

<use>dev_setup</use>

</connection>

</core_setup>

</resources>

</global>

</config>

Now Magento will try to use “dev_dbuser” user with the “dev_password” password and connect to the “dev_magento_db” database.

I tried to use xdebug putting break point in Mage_Core_Moel_Config:: _loadDeclaredModules(); but the function is not executed so I cannot see what actually happens inside. I believe this module should be executed each time because we may disable any module.

@Dgent
I do not know why you had problems with xDebug. Here is screenshot of my IDE with breakpoint in _loadDeclaredModules() method.
This method operates with “depends” and “active” nodes. But if Magento config cache is enabled final xml is taken from the cache storage and method is not executed.

I just check your problem It seems that if you change your file name custom.xml to my.xml then it should be work CAUSE if there are bunch of the xml files are in app/etc/*.xml then the finally merged file in the loadBase() will be result of all files(merged) in alphabetical order. I hope this make sense to you.

Nice post! Before hire Magento developer companies are checking whether the developer whom they are hiring is certified in Magento or not, affordable or not, skilled or not, then only it would be a worth deal for them..