****************************************************************************
Mage_core_mode_config
的init过程。
/**
* Initialization of core configuration
*
* @return Mage_Core_Model_Config
*/
public function init($options=array())
{
$this->setCacheChecksum(null);
$this->_cacheLoadedSections = array();
$this->setOptions($options);
$this->loadBase();
$cacheLoad = $this->loadModulesCache();
if ($cacheLoad) {
return $this;
}
$this->loadModules();
$this->loadDb();
$this->saveCache();
return $this;
}
1.
$this->setCacheChecksum(null);
/**
* Enter description here...
*
* @param string $data
* @return Varien_Simplexml_Config
*/
public function setCacheChecksum($data)
{
if (is_null($data)) {
$this->_cacheChecksum = null;
} elseif (false===$data || 0===$data) {
$this->_cacheChecksum = false;
} else {
$this->_cacheChecksum = md5($data);
}
return $this;
}
//总结:
对$data用md5加密。然后赋值给$this->_cacheChecksum.
2
$this->_cacheLoadedSections = array();
/**
* Loaded Configuration by cached sections
*
* @var array
*/
protected $_cacheLoadedSections = array();
3
$this->setOptions($options);
如果传入的数据中有$options,则赋值
$this->getOptions()->addData($options);
4
$this->loadBase();
/**
* Load base system configuration (config.xml and local.xml files)
*
* @return Mage_Core_Model_Config
*/
public function loadBase()
{
$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;
}
4.1
$etcDir = $this->getOptions()->getEtcDir();
4.1.1
//MAGE_CORE_MODEL_CONFIG_OPTIONS
public function getEtcDir()
{
//return $this->getDataSetDefault('etc_dir', $this->getAppDir().DS.'etc');
return $this->_data['etc_dir'];
}
在 MAGE_CORE_MODEL_CONFIG_OPTIONS 初始化函数里面:
$this->_data['etc_dir'] = $appRoot.DS.'etc';
//总结
得到的是app/ect
4.2
//glob()函数的作用是:以数组的形式返回与指定模式相匹配的文件名或目录
$files = glob($etcDir.DS.'*.xml');
//app/etc下面的所有配置文件。
4.3
$this->loadFile(current($files));
4.3.1
current (array &$array)
//return mixed The current function simply returns the
* value of the array element that's currently being pointed to by the
* internal pointer. It does not move the pointer in any way. If the
* internal pointer points beyond the end of the elements list or the array is
* empty, current returns false.
4.3.2
/**
* Imports XML file
*
* @param string $filePath
* @return boolean
*/
public function loadFile($filePath)
{
if (!is_readable($filePath)) {
//throw new Exception('Can not read xml file '.$filePath);
return false;
}
$fileData = file_get_contents($filePath);
$fileData = $this->processFileData($fileData);
return $this->loadString($fileData, $this->_elementClass);
}
4.3.2.1
// Reads entire file into a string
$fileData = file_get_contents($filePath);
4.3.2.2
// processFileData
/**
* Stub method for processing file data right after loading the file text
*
* @param string $text
* @return string
*/
public function processFileData($text)
{
return $text;
}
4.3.2.3
//$this->loadString($fileData, $this->_elementClass);
/**
* Imports XML string
*
* @param string $string
* @return boolean
*/
public function loadString($string)
{
if (is_string($string)) {
$xml = simplexml_load_string($string, $this->_elementClass);
if ($xml instanceof Varien_Simplexml_Element) {
$this->_xml = $xml;
return true;
}
} else {
Mage::logException(new Exception('"$string" parameter for simplexml_load_string is not a string'));
}
return false;
}
4.3.2.3.1
$fileData = file_get_contents($filePath);
$this->_elementClass就是在mode/config/base.php初始化的时候,赋值的
$this->_elementClass = 'Mage_Core_Model_Config_Element';
4.3.2.3.2
//Interprets a string of XML into an object
//return SimpleXMLElement an object of class SimpleXMLElement with
* properties containing the data held within the XML document
simplexml_load_string()
通过一个xml文件,返回一个SimpleXMLElement类型的对象。
//
$xml = simplexml_load_string($string, $this->_elementClass);
从这里看。貌似mage_core_model_config_element是从把string变成xml对象(Varien_Simplexml_Element类型的对象)服务的。
4.3.2.3.3
$xml instanceof Varien_Simplexml_Element
判断$xml是否为Varien_Simplexml_Element()类型的对象。
小结:首先找到配置文件目录,然后通过file_get_contents($filePath),把文件读取到string中,通过$xml = simplexml_load_string($string, $this->_elementClass),
生成Varien_Simplexml_Element()类型的对象。
$this->loadFile(current($files));的作用就是读取xml文件,生成Varien_Simplexml_Element,赋值于$this->_xml.
故mage_core_model_config_element为读取xml生成varien_simplexml_element对象。
4.4
$merge = clone $this->_prototype;
$merge->loadFile($file);
$this->extend($merge);
4.4.1
$merge->loadFile($file);
和4.3---$this->loadFile(),是一样的效果,不过他写入的类是:mage_core_model_config_base 生成的对象$merge的属性--->_xml(varien_simplexml_Element),
4.4.2
$this->extend($merge);
/**
* Enter description here...
*
* @param Varien_Simplexml_Config $config
* @param boolean $overwrite
* @return Varien_Simplexml_Config
*/
public function extend(Varien_Simplexml_Config $config, $overwrite=true)
{
$this->getNode()->extend($config->getNode(), $overwrite);
return $this;
}
4.4.2.1
$this->getNode();
/**
* Returns node found by the $path
*
* @see Varien_Simplexml_Element::descend
* @param string $path
* @return Varien_Simplexml_Element
*/
public function getNode($path=null)
{
if (!$this->_xml instanceof Varien_Simplexml_Element) {
return false;
} elseif ($path === null) {
return $this->_xml;
} else {
return $this->_xml->descend($path);
}
}
//
如果$path不是Varien_simplexml_element,则return flase
//
如果$path是null,返回xml,
//
如果不为空,则返回$this->_xml->descend($path);
4.4.2.2
$this->getNode()->extend($config->getNode(), $overwrite);
//$this->getNode()返回的是一个varien_simplexml_element()对象类型。
/**
* Extends current node with xml from $source
*
* If $overwrite is false will merge only missing nodes
* Otherwise will overwrite existing nodes
*
* @param Varien_Simplexml_Element $source
* @param boolean $overwrite
* @return Varien_Simplexml_Element
*/
public function extend($source, $overwrite=false)
{
if (!$source instanceof Varien_Simplexml_Element) {
return $this;
}
foreach ($source->children() as $child) {
$this->extendChild($child, $overwrite);
}
return $this;
}
4.4.2.2.1
$source->children()
//PHP库函数,Finds children of given node
public function children ($ns = null, $is_prefix = null) {}
4.4.2.2.2
//扩展一个子节点
$this->extendChild($child, $overwrite);
/**
* Extends one node
*
* @param Varien_Simplexml_Element $source
* @param boolean $overwrite
* @return Varien_Simplexml_Element
*/
public function extendChild($source, $overwrite=false)
{
// this will be our new target node
$targetChild = null;
// name of the source node
$sourceName = $source->getName();
// here we have children of our source node
$sourceChildren = $source->children();
if (!$source->hasChildren()) {
// handle string node
if (isset($this->$sourceName)) {
// if target already has children return without regard
if ($this->$sourceName->children()) {
return $this;
}
if ($overwrite) {
unset($this->$sourceName);
} else {
return $this;
}
}
$targetChild = $this->addChild($sourceName, $source->xmlentities());
$targetChild->setParent($this);
foreach ($source->attributes() as $key=>$value) {
$targetChild->addAttribute($key, $this->xmlentities($value));
}
return $this;
}
if (isset($this->$sourceName)) {
$targetChild = $this->$sourceName;
}
if (is_null($targetChild)) {
// if child target is not found create new and descend
$targetChild = $this->addChild($sourceName);
$targetChild->setParent($this);
foreach ($source->attributes() as $key=>$value) {
$targetChild->addAttribute($key, $this->xmlentities($value));
}
}
// finally add our source node children to resulting new target node
foreach ($sourceChildren as $childKey=>$childNode) {
$targetChild->extendChild($childNode, $overwrite);
}
return $this;
}
//小结:
将每个xml文件生成的varien_simplexml_element(加载xml),然后通过$this->extend()方法加载原理是:
while ($file = next($files)) {
$merge = clone $this->_prototype;
$merge->loadFile($file);
$this->extend($merge);
}
//return Varien_Simplexml_Config
$this->extend($merge);
//总结:
loadBase函数,读取app/etc/ 下面的所有xml文件,生成varien_simplexml_element对象,赋值于mage_core_model_config 的属性 _xml ,然后mage_core_model_config->loadFole(current($files)),也就是mage_core_model_config读取files数组里面的第一个file,加载,然后通过,This->_prototype(mage_core_model_base),读取next(files),$this->extend((clone $this->_prototype)->loadFile($file));
extend()函数加载子节点
$this为mage_core_model_config;
(clone $this->_prototype)->loadFile($file)为加载xml文件生成varien_simplexml_element对象。
while ($file = next($files)) {
$merge = clone $this->_prototype;
$merge->loadFile($file);
$this->extend($merge);
}
总结:
1.首先mage_core_model_config->loadFile()加载第一个file生成varien_simplexml_element,
2剩下的file,通过mage_core_model_config_base->loadFile($file)加载,
3将mage_core_model_config和mage_core_model_config_base合并
mage_core_model_config->extend(mage_core_model_config_base).
//@return Mage_Core_Model_Config
$this->loadBase();
加载app/etc/下面的所有的xml文件,然后赋值于Mage_Core_Model_Config->_xml.
完成对所有xml文件的加载。
4.5
if (in_array($etcDir.DS.'local.xml', $files)) {
$this->_isLocalConfigLoaded = true;
}
//Checks if a value exists in an array
in_array
/**
* Flag which identify what local configuration is loaded
*
* @var bool
*/
protected $_isLocalConfigLoaded = false;
5
$cacheLoad = $this->loadModulesCache();
if ($cacheLoad) {
return $this;
}
5.1
//$this->loadModulesCache();
/**
* Load cached modules configuration
*
* @return bool
*/
public function loadModulesCache()
{
if (Mage::isInstalled()) {
if ($this->_canUseCacheForInit()) {
Varien_Profiler::start('mage::app::init::config::load_cache');
$loaded = $this->loadCache();
Varien_Profiler::stop('mage::app::init::config::load_cache');
if ($loaded) {
$this->_useCache = true;
return true;
}
}
}
return false;
}
5.1.1
Mage::isInstalled()
/**
* Retrieve application installation flag
*
* @param string|array $options
* @return bool
*/
public static function isInstalled($options = array())
{
if (self::$_isInstalled === null) {
self::setRoot();
if (is_string($options)) {
$options = array('etc_dir' => $options);
}
$etcDir = 'etc';
if (!empty($options['etc_dir'])) {
$etcDir = $options['etc_dir'];
}
$localConfigFile = self::getRoot() . DS . $etcDir . DS . 'local.xml';
self::$_isInstalled = false;
if (is_readable($localConfigFile)) {
$localConfig = simplexml_load_file($localConfigFile);
date_default_timezone_set('UTC');
if (($date = $localConfig->global->install->date) && strtotime($date)) {
self::$_isInstalled = true;
}
}
}
return self::$_isInstalled;
}
5.1.1.1
// self::setRoot();
/**
* Set application root absolute path
*
* @param string $appRoot
* @throws Mage_Core_Exception
*/
public static function setRoot($appRoot = '')
{
if (self::$_appRoot) {
return ;
}
if ('' === $appRoot) {
// automagically find application root by dirname of Mage.php
$appRoot = dirname(__FILE__);
}
$appRoot = realpath($appRoot);
if (is_dir($appRoot) and is_readable($appRoot)) {
self::$_appRoot = $appRoot;
} else {
self::throwException($appRoot . ' is not a directory or not readable by this user');
}
}
5.1.2
$this->_canUseCacheForInit()
/**
* Check if cache can be used for config initialization
*
* @return bool
*/
protected function _canUseCacheForInit()
{
return Mage::app()->useCache('config') && $this->_allowCacheForInit
&& !$this->_loadCache($this->_getCacheLockId());
}
5.1.2.1
Mage::app()->useCache('config')
/**
* Check whether to use cache for specific component
*
* @return boolean
*/
public function useCache($type=null)
{
return $this->_cache->canUse($type);
}
5.1.2.1.1
/**
* Cache object
*
* @var Zend_Cache_Core
*/
protected $_cache;
5.1.2.2
$this->_allowCacheForInit
/**
* Flach which allow using cache for config initialization
*
* @var bool
*/
protected $_allowCacheForInit = true;
5.1.2.3
$this->_loadCache($this->_getCacheLockId());
5.1.2.3.1
/**
* Get lock flag cache identifier
*
* @return string
*/
protected function _getCacheLockId()
{
return $this->getCacheId().'.lock';
}
5.1.2.3.1.1
/**
* Enter description here...
*
* @return string
*/
public function getCacheId()
{
return $this->_cacheId;
}
5.1.2.3.2
$this->_loadCache()
/**
* Load cached data by identifier
*
* @param string $id
* @return string
*/
protected function _loadCache($id)
{
return Mage::app()->loadCache($id);
}
5.1.2.3.2.1
/**
* Loading cache data
*
* @param string $id
* @return mixed
*/
public function loadCache($id)
{
return $this->_cache->load($id);
}
5.1.3
$loaded = $this->loadCache();
/**
* Enter description here...
*
* @return boolean
*/
public function loadCache()
{
if (!$this->validateCacheChecksum()) {
return false;
}
$xmlString = $this->_loadCache($this->getCacheId());
$xml = simplexml_load_string($xmlString, $this->_elementClass);
if ($xml) {
$this->_xml = $xml;
$this->setCacheSaved(true);
return true;
}
return false;
}
6
$this->loadModules();
6.1
/**
* Load modules configuration
*
* @return Mage_Core_Model_Config
*/
public function loadModules()
{
Varien_Profiler::start('config/load-modules');
$this->_loadDeclaredModules();
$this->loadModulesConfiguration('config.xml', $this);
/**
* Prevent local.xml directives overwriting
*/
$mergeConfig = clone $this->_prototype;
$this->_isLocalConfigLoaded = $mergeConfig->loadFile($this->getOptions()->getEtcDir().DS.'local.xml');
if ($this->_isLocalConfigLoaded) {
$this->extend($mergeConfig);
}
$this->applyExtends();
Varien_Profiler::stop('config/load-modules');
return $this;
}
6.1.1
$this->_loadDeclaredModules();
/**
* Load declared modules configuration
*
* @param null $mergeConfig depricated
* @return Mage_Core_Model_Config
*/
protected function _loadDeclaredModules($mergeConfig = null)
{
$moduleFiles = $this->_getDeclaredModuleFiles();
if (!$moduleFiles) {
return ;
}
Varien_Profiler::start('config/load-modules-declaration');
$unsortedConfig = new Mage_Core_Model_Config_Base();
$unsortedConfig->loadString('<config/>');
$fileConfig = new Mage_Core_Model_Config_Base();
// load modules declarations
foreach ($moduleFiles as $file) {
$fileConfig->loadFile($file);
$unsortedConfig->extend($fileConfig);
}
$moduleDepends = array();
foreach ($unsortedConfig->getNode('modules')->children() as $moduleName => $moduleNode) {
$depends = array();
if ($moduleNode->depends) {
foreach ($moduleNode->depends->children() as $depend) {
$depends[$depend->getName()] = true;
}
}
$moduleDepends[$moduleName] = array(
'module' => $moduleName,
'depends' => $depends,
'active' => ('true' === (string)$moduleNode->active ? true : false),
);
}
// check and sort module dependens
$moduleDepends = $this->_sortModuleDepends($moduleDepends);
// create sorted config
$sortedConfig = new Mage_Core_Model_Config_Base();
$sortedConfig->loadString('<config><modules/></config>');
foreach ($unsortedConfig->getNode()->children() as $nodeName => $node) {
if ($nodeName != 'modules') {
$sortedConfig->getNode()->appendChild($node);
}
}
foreach ($moduleDepends as $moduleProp) {
$node = $unsortedConfig->getNode('modules/'.$moduleProp['module']);
$sortedConfig->getNode('modules')->appendChild($node);
}
$this->extend($sortedConfig);
Varien_Profiler::stop('config/load-modules-declaration');
return $this;
}
6.1.1.1
//还不是很明白,应该是得到$string="<config.>"节点下所有数据的配置吧。类型为element。
/**
* Imports XML string
*
* @param string $string
* @return boolean
*/
public function loadString($string)
{
if (is_string($string)) {
$xml = simplexml_load_string($string, $this->_elementClass);
if ($xml instanceof Varien_Simplexml_Element) {
$this->_xml = $xml;
return true;
}
} else {
Mage::logException(new Exception('"$string" parameter for simplexml_load_string is not a string'));
}
return false;
}
//Interprets a string of XML into an object
//返回类 SimpleXMLElement 的一个对象,该对象的属性包含 XML 文档中的数据
$xml = simplexml_load_string($string, $this->_elementClass);
6.1.2
$this->loadModulesConfiguration('config.xml', $this);
//整合所有active的modules,然后把etc里面的内容整合。
//config-》loadString('<config/>');得到只有<config>子节点所在的xml的mage_core_model_config_element类型
/**
* Iterate all active modules "etc" folders and combine data from
* specidied xml file name to one object
*
* @param string $fileName
* @param null|Mage_Core_Model_Config_Base $mergeToObject
* @return Mage_Core_Model_Config_Base
*/
public function loadModulesConfiguration($fileName, $mergeToObject = null, $mergeModel=null)
{
$disableLocalModules = !$this->_canUseLocalModules();
if ($mergeToObject === null) {
$mergeToObject = clone $this->_prototype;
$mergeToObject->loadString('<config/>');
}
if ($mergeModel === null) {
$mergeModel = clone $this->_prototype;
}
$modules = $this->getNode('modules')->children();
foreach ($modules as $modName=>$module) {
if ($module->is('active')) {
if ($disableLocalModules && ('local' === (string)$module->codePool)) {
continue;
}
$configFile = $this->getModuleDir('etc', $modName).DS.$fileName;
if ($mergeModel->loadFile($configFile)) {
$mergeToObject->extend($mergeModel, true);
}
}
}
return $mergeToObject;
}
6.1.3
$mergeConfig = clone $this->_prototype;
$this->_isLocalConfigLoaded = $mergeConfig->loadFile($this->getOptions()->getEtcDir().DS.'local.xml');
6.1.4
$this->extend($mergeConfig);
6.1.5
$this->applyExtends();
7
$this->loadDb();
/**
* Load config data from DB
*
* @return Mage_Core_Model_Config
*/
public function loadDb()
{
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;
}
7.1
$dbConf = $this->getResourceModel();
/**
* Get config resource model
*
* @return Mage_Core_Store_Mysql4_Config
*/
public function getResourceModel()
{
if (is_null($this->_resourceModel)) {
$this->_resourceModel = Mage::getResourceModel('core/config');
}
return $this->_resourceModel;
}
7.2
$dbConf->loadToXml($this);
/**
* Load configuration values into xml config object
*
* @param Mage_Core_Model_Config $xmlConfig
* @param string $cond
* @return Mage_Core_Model_Mysql4_Config_Collection
*/
public function loadToXml(Mage_Core_Model_Config $xmlConfig, $cond=null)
8
$this->saveCache();
/**
* Save configuration cache
*
* @param array $tags cache tags
* @return Mage_Core_Model_Config
*/
public function saveCache($tags=array())
{
if (!Mage::app()->useCache('config')) {
return $this;
}
if (!in_array(self::CACHE_TAG, $tags)) {
$tags[] = self::CACHE_TAG;
}
$cacheLockId = $this->_getCacheLockId();
if ($this->_loadCache($cacheLockId)) {
return $this;
}
if (!empty($this->_cacheSections)) {
$xml = clone $this->_xml;
foreach ($this->_cacheSections as $sectionName => $level) {
$this->_saveSectionCache($this->getCacheId(), $sectionName, $xml, $level, $tags);
unset($xml->$sectionName);
}
$this->_cachePartsForSave[$this->getCacheId()] = $xml->asNiceXml('', false);
} else {
return parent::saveCache($tags);
}
$this->_saveCache(time(), $cacheLockId, array(), 60);
$this->removeCache();
foreach ($this->_cachePartsForSave as $cacheId => $cacheData) {
$this->_saveCache($cacheData, $cacheId, $tags, $this->getCacheLifetime());
}
unset($this->_cachePartsForSave);
$this->_removeCache($cacheLockId);
return $this;
}
8
$this->saveCache();
7.2
$dbConf->loadToXml($this);
5.1.3
$loaded = $this->loadCache();
6$this->loadModules();
需要在细致搞搞!!