Skip to content
This repository

Environment based local.xml merging #41

Closed
wants to merge 1 commit into from

3 participants

Vinai Kopp Matthias Zeis
Vinai Kopp
Vinai commented July 11, 2012

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
#7

Vinai Kopp 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
magento/magento2#7
a60099d
Matthias Zeis
mzeis commented July 13, 2012

Thanks Vinai for the implementation.

I tested these scenarios successfully:

  • use a different adminhtml frontName
  • use a different database name

If somebody wants to try this, follow these steps:

  • clone Vinais repository (https://github.com/Vinai/magento2.git) and checkout branch local.xml-override
  • install Magento
  • disable caches (this one is important as the config will be cached)
  • add MAGE_APPLICATION_ENV to your vHost config or .htaccess
    • e.g. SetEnv MAGE_APPLICATION_ENV dev
    • If you use .htaccess, edit the file in the Magento root directory, not pub/.htaccess
  • add your environment local.xml (e.g. local.dev.xml) and override the settings you want to test
Owner

Instead of applying the proposed patch, we have implemented it in different way.

Most of modifications will be concentrated in loadBase() method. New algorithm:
1. Scan app/etc directory for all files with .xml extension
2. Merge all the found files, except local.xml, in alphabetical order
3. If the local.xml is found – merge it after all the files
4. If the configuration option (Mage_Core_Model_Config_Options) "local_config" is provided (originates from MAGE_LOCAL_CONFIG environment variable), assess if it matches pattern and load additional file:

  • Pattern: alphanumeric or dash or underscore, then "/", then again alphanumeric or dash or underscore, then ".xml"
  • The file will be loaded only if local.xml has been loaded. If local.xml doesn't exist, the file will not be loaded.
  • If the declared file not found, it will be skipped.

This change will be rolled out in one of next updates.
Thank you for the idea and actual suggested implementation.

mage2-team closed this July 25, 2012
Vinai Kopp
Vinai commented July 28, 2012

Thank you for the detailed answer!
The patch isn't in the current version of github yet, is it?
I like the idea of MAGE_LOCAL_CONFIG to configure config options, but is it possible to specify an php array using, lets say apache mod_env?

mage2-team referenced this pull request from a commit August 01, 2012
Update as of 8/1/2012
* Refactored ACL for the backend
  * ACL resources
    * Strict configuration format, validated by XSD schema
    * ACL configuration relocation from `app/code/<pool>/<namespace>/<module>/etc/adminhtml.xml` to `app/code/<pool>/<namespace>/<module>/etc/adminhtml/acl.xml`
    * Renamed ACL resource identifiers according to the format `<namespace>_<module>::<resource>` throughout the system
      * Backend menu configuration requires to specify ACL resource identifier in the new format
      * Explicit declaration of ACL resources in `app/code/<pool>/<namespace>/<module>/etc/system.xml` instead of implicit relation by XPath
    * Migration tool `dev/tools/migration/acl.php` to convert ACL configuration from 1.x to 2.x
  * Declaration of ACL resource/role/rule loaders through the area configuration
    * Module `Mage_Backend` declares loader for ACL resources in backend area
    * Module `Mage_User` declares loaders for ACL roles and rules (relations between roles and resources) in backend area
  * Implemented integrity and legacy tests for ACL
* Fixed issues:
  * Losing qty and visibility information when importing products
  * Impossibility to reload captcha on backend
  * Temporary excluded from execution integration test `Mage_Review_Model_Resource_Review_Product_CollectionTest::testGetResultingIds()` and corresponding fixture script, which cause occasional `segmentation fault` (exit code 139)
* Refactored methods with high cyclomatic complexity:
  * `Mage_Adminhtml_Block_System_Store_Edit_Form::_prepareForm()`
  * `Mage_Adminhtml_Block_System_Config_Form::initForm()`
  * `Mage_Adminhtml_Block_System_Config_Form::initFields()`
* GitHub requests:
  * [#32](#32) -- fixed declaration of localization CSV files
  * [#35](#35) -- removed non-used `Mage_Core_Block_Flush` block
  * [#41](#41) -- implemented ability to extends `app/etc/local.xml` by specifying additional config file via `MAGE_LOCAL_CONFIG` environment variable
7fec10a
mage2-team referenced this pull request from a commit August 01, 2012
Update as of 8/2/2012
* Refactored ACL for the backend
  * ACL resources
    * Strict configuration format, validated by XSD schema
    * ACL configuration relocation from `app/code/<pool>/<namespace>/<module>/etc/adminhtml.xml` to `app/code/<pool>/<namespace>/<module>/etc/adminhtml/acl.xml`
    * Renamed ACL resource identifiers according to the format `<namespace>_<module>::<resource>` throughout the system
      * Backend menu configuration requires to specify ACL resource identifier in the new format
      * Explicit declaration of ACL resources in `app/code/<pool>/<namespace>/<module>/etc/system.xml` instead of implicit relation by XPath
    * Migration tool `dev/tools/migration/acl.php` to convert ACL configuration from 1.x to 2.x
  * Declaration of ACL resource/role/rule loaders through the area configuration
    * Module `Mage_Backend` declares loader for ACL resources in backend area
    * Module `Mage_User` declares loaders for ACL roles and rules (relations between roles and resources) in backend area
  * Implemented integrity and legacy tests for ACL
* Fixed issues:
  * Losing qty and visibility information when importing products
  * Impossibility to reload captcha on backend
  * Temporary excluded from execution integration test `Mage_Review_Model_Resource_Review_Product_CollectionTest::testGetResultingIds()` and corresponding fixture script, which cause occasional `segmentation fault` (exit code 139)
* Refactored methods with high cyclomatic complexity:
  * `Mage_Adminhtml_Block_System_Store_Edit_Form::_prepareForm()`
  * `Mage_Adminhtml_Block_System_Config_Form::initForm()`
  * `Mage_Adminhtml_Block_System_Config_Form::initFields()`
* GitHub requests:
  * [#32](#32) -- fixed declaration of localization CSV files
  * [#35](#35) -- removed non-used `Mage_Core_Block_Flush` block
  * [#41](#41) -- implemented ability to extends `app/etc/local.xml` by specifying additional config file via `MAGE_LOCAL_CONFIG` environment variable
b370593
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Showing 1 unique commit by 1 author.

Jul 11, 2012
Vinai Kopp 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
magento/magento2#7
a60099d
This page is out of date. Refresh to see the latest.

Showing 1 changed file with 112 additions and 18 deletions. Show diff stats Hide diff stats

  1. 130  app/code/core/Mage/Core/Model/Config.php
130  app/code/core/Mage/Core/Model/Config.php
@@ -48,7 +48,7 @@ class Mage_Core_Model_Config extends Mage_Core_Model_Config_Base
48 48
      * array(
49 49
      *      $sectionName => $recursionLevel
50 50
      * )
51  
-     * Recursion level provide availability cache subnodes separatly
  51
+     * Recursion level provide availability cache subnodes separately
52 52
      *
53 53
      * @var array
54 54
      */
@@ -147,7 +147,7 @@ class Mage_Core_Model_Config extends Mage_Core_Model_Config_Base
147 147
     protected $_cachePartsForSave = array();
148 148
 
149 149
     /**
150  
-     * Empty configuration object for loading and megring configuration parts
  150
+     * Empty configuration object for loading and merging configuration parts
151 151
      *
152 152
      * @var Mage_Core_Model_Config_Base
153 153
      */
@@ -161,6 +161,20 @@ class Mage_Core_Model_Config extends Mage_Core_Model_Config_Base
161 161
     protected $_isLocalConfigLoaded = false;
162 162
 
163 163
     /**
  164
+     * Ordered list of config files loaded as the local configuration
  165
+     *
  166
+     * @var array
  167
+     */
  168
+    protected $_localConfigFiles = null;
  169
+
  170
+    /**
  171
+     * Temporary model cache to avoid multiple parsing of local.xml files.
  172
+     *
  173
+     * @var Mage_Core_Model_Config_Base
  174
+     */
  175
+    protected $_localConfigMergeCache = null;
  176
+
  177
+    /**
164 178
      * Flag which allow to use modules from local code pool
165 179
      *
166 180
      * @var bool
@@ -253,11 +267,13 @@ public function init($options=array())
253 267
 
254 268
         $cacheLoad = $this->loadModulesCache();
255 269
         if ($cacheLoad) {
  270
+            $this->_cleanLoadCache();
256 271
             return $this;
257 272
         }
258 273
         $this->loadModules();
259 274
         $this->loadDb();
260 275
         $this->saveCache();
  276
+        $this->_cleanLoadCache();
261 277
         return $this;
262 278
     }
263 279
 
@@ -269,16 +285,29 @@ public function init($options=array())
269 285
     public function loadBase()
270 286
     {
271 287
         $etcDir = $this->getOptions()->getEtcDir();
272  
-        $files = glob($etcDir.DS.'*.xml');
273  
-        $this->loadFile(current($files));
274  
-        while ($file = next($files)) {
275  
-            $merge = clone $this->_prototype;
276  
-            $merge->loadFile($file);
277  
-            $this->extend($merge);
278  
-        }
279  
-        if (in_array($etcDir.DS.'local.xml', $files)) {
280  
-            $this->_isLocalConfigLoaded = true;
281  
-        }
  288
+        $localConfigs = $this->_getLocalConfigFiles();
  289
+
  290
+        $files = glob($etcDir . DS . '*.xml');
  291
+        $file = current($files);
  292
+        do {
  293
+            // Skip local.xml config files initially
  294
+            if (in_array($file, $localConfigs)) {
  295
+                continue;
  296
+            }
  297
+            if ($this->getNode()) {
  298
+                // Extend current XML with following files
  299
+                $merge = clone $this->_prototype;
  300
+                $merge->loadFile($file);
  301
+                $this->extend($merge);
  302
+            } else {
  303
+                // Load the first file directly
  304
+                $this->loadFile($file);
  305
+            }
  306
+        } while ($file = next($files));
  307
+
  308
+        // Load local.xml configuration files last so they have a higher priority
  309
+        $this->loadLocalConfig();
  310
+
282 311
         return $this;
283 312
     }
284 313
 
@@ -315,16 +344,12 @@ public function loadModules()
315 344
         $this->_loadDeclaredModules();
316 345
 
317 346
         $resourceConfig = sprintf('config.%s.xml', $this->_getResourceConnectionModel('core'));
318  
-        $this->loadModulesConfiguration(array('config.xml',$resourceConfig), $this);
  347
+        $this->loadModulesConfiguration(array('config.xml', $resourceConfig), $this);
319 348
 
320 349
         /**
321 350
          * Prevent local.xml directives overwriting
322 351
          */
323  
-        $mergeConfig = clone $this->_prototype;
324  
-        $this->_isLocalConfigLoaded = $mergeConfig->loadFile($this->getOptions()->getEtcDir().DS.'local.xml');
325  
-        if ($this->_isLocalConfigLoaded) {
326  
-            $this->extend($mergeConfig);
327  
-        }
  352
+        $this->loadLocalConfig();
328 353
 
329 354
         $this->applyExtends();
330 355
         Magento_Profiler::stop('load_modules');
@@ -333,6 +358,75 @@ public function loadModules()
333 358
     }
334 359
 
335 360
     /**
  361
+     * Return a list of local.xml config files
  362
+     *
  363
+     * The environment dependant local configuration file can be specified
  364
+     * using the environment variable $_SERVER['MAGE_APPLICATION_ENV'];
  365
+     *
  366
+     * @return array
  367
+     */
  368
+    protected function _getLocalConfigFiles()
  369
+    {
  370
+        if (!isset($this->_localConfigFiles)) {
  371
+            $this->_localConfigFiles = array($this->getOptions()->getEtcDir() . DS . 'local.xml');
  372
+            $env = false;
  373
+            if (isset($_SERVER) && is_array($_SERVER) && isset($_SERVER['MAGE_APPLICATION_ENV'])) {
  374
+                $env = $_SERVER['MAGE_APPLICATION_ENV'];
  375
+            }
  376
+            if (isset($env) && is_string($env)) {
  377
+                if (preg_match('/^[a-z0-9_-]+$/', $env)) {
  378
+                    $file = $this->getOptions()->getEtcDir() . DS . 'local.' . $env . '.xml';
  379
+                    if (file_exists($file)) {
  380
+                        $this->_localConfigFiles[] = $file;
  381
+                    }
  382
+                }
  383
+            }
  384
+        }
  385
+        return $this->_localConfigFiles;
  386
+    }
  387
+
  388
+    /**
  389
+     * Load the local.xml file, followed by a local.$env.xml file if configured
  390
+     *
  391
+     * @return Mage_Core_Model_Config
  392
+     */
  393
+    public function loadLocalConfig()
  394
+    {
  395
+        if (is_null($this->_localConfigMergeCache)) {
  396
+            $this->_localConfigMergeCache = clone $this->_prototype;
  397
+            foreach ($this->_getLocalConfigFiles() as $file) {
  398
+                if ($this->_localConfigMergeCache->getNode()) {
  399
+                    $mergeConfig = clone $this->_prototype;
  400
+                    $result = $mergeConfig->loadFile($file);
  401
+                    if ($result) {
  402
+                        $this->_localConfigMergeCache->extend($mergeConfig);
  403
+                    }
  404
+                } else {
  405
+                    $result = $this->_localConfigMergeCache->loadFile($file);
  406
+                }
  407
+                // At least one local.xml config file needs to be loaded
  408
+                $this->_isLocalConfigLoaded = $this->_isLocalConfigLoaded || $result;
  409
+            }
  410
+        }
  411
+        if ($this->_isLocalConfigLoaded) {
  412
+            $this->extend($this->_localConfigMergeCache);
  413
+        }
  414
+        return $this;
  415
+    }
  416
+
  417
+    /**
  418
+     * Unset the local config merge cache instance
  419
+     *
  420
+     * @return Mage_Core_Model_Config
  421
+     * @see self::loadLocalConfig()
  422
+     */
  423
+    protected function _cleanLoadCache()
  424
+    {
  425
+        $this->_localConfigMergeCache = null;
  426
+        return $this;
  427
+    }
  428
+
  429
+    /**
336 430
      * Check if local configuration (DB connection, etc) is loaded
337 431
      *
338 432
      * @return bool
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.