From a60099d859f1d0962557660007bfcb4cf62943b9 Mon Sep 17 00:00:00 2001 From: Vinai Kopp Date: Wed, 11 Jul 2012 15:39:25 +0200 Subject: [PATCH] Environment based local.xml merging Support merging an additional local.xml file based on the value of the MAGE_APPLICATION_ENV environment variable. The name of the file will be built as follows: 'app/etc/local.' . $_SERVER['MAGE_APPLICATION_ENV'] . '.xml' The value of the variable is checked to contain only letters, characters, underscores and dashes. The file will be merged after the regular local.xml file. The background idea is described by Matthias Zeis at https://github.com/magento/magento2/issues/7 --- app/code/core/Mage/Core/Model/Config.php | 130 +++++++++++++++++++---- 1 file changed, 112 insertions(+), 18 deletions(-) diff --git a/app/code/core/Mage/Core/Model/Config.php b/app/code/core/Mage/Core/Model/Config.php index e02e0583fcbf1..0a30d30053ba3 100644 --- a/app/code/core/Mage/Core/Model/Config.php +++ b/app/code/core/Mage/Core/Model/Config.php @@ -48,7 +48,7 @@ class Mage_Core_Model_Config extends Mage_Core_Model_Config_Base * array( * $sectionName => $recursionLevel * ) - * Recursion level provide availability cache subnodes separatly + * Recursion level provide availability cache subnodes separately * * @var array */ @@ -147,7 +147,7 @@ class Mage_Core_Model_Config extends Mage_Core_Model_Config_Base protected $_cachePartsForSave = array(); /** - * Empty configuration object for loading and megring configuration parts + * Empty configuration object for loading and merging configuration parts * * @var Mage_Core_Model_Config_Base */ @@ -160,6 +160,20 @@ class Mage_Core_Model_Config extends Mage_Core_Model_Config_Base */ protected $_isLocalConfigLoaded = false; + /** + * Ordered list of config files loaded as the local configuration + * + * @var array + */ + protected $_localConfigFiles = null; + + /** + * Temporary model cache to avoid multiple parsing of local.xml files. + * + * @var Mage_Core_Model_Config_Base + */ + protected $_localConfigMergeCache = null; + /** * Flag which allow to use modules from local code pool * @@ -253,11 +267,13 @@ public function init($options=array()) $cacheLoad = $this->loadModulesCache(); if ($cacheLoad) { + $this->_cleanLoadCache(); return $this; } $this->loadModules(); $this->loadDb(); $this->saveCache(); + $this->_cleanLoadCache(); return $this; } @@ -269,16 +285,29 @@ public function init($options=array()) 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; - } + $localConfigs = $this->_getLocalConfigFiles(); + + $files = glob($etcDir . DS . '*.xml'); + $file = current($files); + do { + // Skip local.xml config files initially + if (in_array($file, $localConfigs)) { + continue; + } + if ($this->getNode()) { + // Extend current XML with following files + $merge = clone $this->_prototype; + $merge->loadFile($file); + $this->extend($merge); + } else { + // Load the first file directly + $this->loadFile($file); + } + } while ($file = next($files)); + + // Load local.xml configuration files last so they have a higher priority + $this->loadLocalConfig(); + return $this; } @@ -315,16 +344,12 @@ public function loadModules() $this->_loadDeclaredModules(); $resourceConfig = sprintf('config.%s.xml', $this->_getResourceConnectionModel('core')); - $this->loadModulesConfiguration(array('config.xml',$resourceConfig), $this); + $this->loadModulesConfiguration(array('config.xml', $resourceConfig), $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->loadLocalConfig(); $this->applyExtends(); Magento_Profiler::stop('load_modules'); @@ -332,6 +357,75 @@ public function loadModules() return $this; } + /** + * Return a list of local.xml config files + * + * The environment dependant local configuration file can be specified + * using the environment variable $_SERVER['MAGE_APPLICATION_ENV']; + * + * @return array + */ + protected function _getLocalConfigFiles() + { + if (!isset($this->_localConfigFiles)) { + $this->_localConfigFiles = array($this->getOptions()->getEtcDir() . DS . 'local.xml'); + $env = false; + if (isset($_SERVER) && is_array($_SERVER) && isset($_SERVER['MAGE_APPLICATION_ENV'])) { + $env = $_SERVER['MAGE_APPLICATION_ENV']; + } + if (isset($env) && is_string($env)) { + if (preg_match('/^[a-z0-9_-]+$/', $env)) { + $file = $this->getOptions()->getEtcDir() . DS . 'local.' . $env . '.xml'; + if (file_exists($file)) { + $this->_localConfigFiles[] = $file; + } + } + } + } + return $this->_localConfigFiles; + } + + /** + * Load the local.xml file, followed by a local.$env.xml file if configured + * + * @return Mage_Core_Model_Config + */ + public function loadLocalConfig() + { + if (is_null($this->_localConfigMergeCache)) { + $this->_localConfigMergeCache = clone $this->_prototype; + foreach ($this->_getLocalConfigFiles() as $file) { + if ($this->_localConfigMergeCache->getNode()) { + $mergeConfig = clone $this->_prototype; + $result = $mergeConfig->loadFile($file); + if ($result) { + $this->_localConfigMergeCache->extend($mergeConfig); + } + } else { + $result = $this->_localConfigMergeCache->loadFile($file); + } + // At least one local.xml config file needs to be loaded + $this->_isLocalConfigLoaded = $this->_isLocalConfigLoaded || $result; + } + } + if ($this->_isLocalConfigLoaded) { + $this->extend($this->_localConfigMergeCache); + } + return $this; + } + + /** + * Unset the local config merge cache instance + * + * @return Mage_Core_Model_Config + * @see self::loadLocalConfig() + */ + protected function _cleanLoadCache() + { + $this->_localConfigMergeCache = null; + return $this; + } + /** * Check if local configuration (DB connection, etc) is loaded *