Skip to content

Fix environment loader #4617

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 24 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
0afa23a
fix: set cache when env loader overrides data
Dec 29, 2024
68c6372
feat?: call env helper on config get
Feb 8, 2025
213d366
feat?: backend: show data from env
Feb 8, 2025
e902db7
feat?: backend: disable field when ENV data is available
Feb 8, 2025
a1c2e76
Update app/code/core/Mage/Adminhtml/Block/System/Config/Form.php
sreichel Feb 8, 2025
f2ef30d
Update app/code/core/Mage/Core/Helper/EnvironmentConfigLoader.php
sreichel Feb 8, 2025
59d3dd2
feat?: backend: do not log on invalid stores - creates infinite loop
Feb 9, 2025
3cda94b
feat: move env variables "str_starts_with"
Feb 17, 2025
8cdbd54
feat: add env flag to disable/enable feature
Feb 17, 2025
0238f4e
fix: fix tests
Feb 17, 2025
03efa93
feat: set disabled, set scope label
Feb 17, 2025
a6630e6
feat: remove checkbox to override
Feb 17, 2025
0cc1bb8
chore: remove inline helper variable name
Feb 17, 2025
08c67a9
Update tests/unit/Mage/Core/Helper/EnvironmentConfigLoaderTest.php
pquerner Feb 17, 2025
e298336
Update tests/unit/Mage/Core/Helper/EnvironmentConfigLoaderTest.php
pquerner Feb 17, 2025
0e7cc02
Update app/code/core/Mage/Core/Helper/EnvironmentConfigLoader.php
pquerner Feb 17, 2025
92f0491
Update app/code/core/Mage/Adminhtml/Block/System/Config/Form.php
pquerner Feb 17, 2025
048a42f
Update tests/unit/Mage/Core/Helper/EnvironmentConfigLoaderTest.php
pquerner Feb 17, 2025
1893538
Update app/code/core/Mage/Adminhtml/Block/System/Config/Form.php
pquerner Feb 18, 2025
0b1dc9a
feat: add "hasPath" test
Feb 18, 2025
bae16d3
feat: add "asArray" test
Feb 18, 2025
1d31f4a
tests: add test cases
Feb 18, 2025
ac99304
Update app/code/core/Mage/Core/Helper/EnvironmentConfigLoader.php
pquerner Mar 9, 2025
36192d8
fix: onStore(re)init the env vars would be lost
Mar 9, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 22 additions & 2 deletions app/code/core/Mage/Adminhtml/Block/System/Config/Form.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class Mage_Adminhtml_Block_System_Config_Form extends Mage_Adminhtml_Block_Widge
public const SCOPE_DEFAULT = 'default';
public const SCOPE_WEBSITES = 'websites';
public const SCOPE_STORES = 'stores';
public const SCOPE_ENV = 'env';

/**
* Config data array
Expand Down Expand Up @@ -79,6 +80,7 @@ public function __construct()
self::SCOPE_DEFAULT => Mage::helper('adminhtml')->__('[GLOBAL]'),
self::SCOPE_WEBSITES => Mage::helper('adminhtml')->__('[WEBSITE]'),
self::SCOPE_STORES => Mage::helper('adminhtml')->__('[STORE VIEW]'),
self::SCOPE_ENV => Mage::helper('adminhtml')->__('[ENV]'),
];
}

Expand Down Expand Up @@ -376,7 +378,7 @@ public function initFields($fieldset, $group, $section, $fieldPrefix = '', $labe
}
}

$field = $fieldset->addField($id, $fieldType, [
$elementFieldData = [
'name' => $name,
'label' => $label,
'comment' => $comment,
Expand All @@ -391,7 +393,14 @@ public function initFields($fieldset, $group, $section, $fieldPrefix = '', $labe
'scope_label' => $this->getScopeLabel($element),
'can_use_default_value' => $this->canUseDefaultValue((int) $element->show_in_default),
'can_use_website_value' => $this->canUseWebsiteValue((int) $element->show_in_website),
]);
];
if ($this->isOverwrittenByEnvVariable($path)) {
$elementFieldData['scope_label'] = $this->_scopeLabels[static::SCOPE_ENV];
$elementFieldData['disabled'] = 1;
$elementFieldData['can_use_default_value'] = 0;
$elementFieldData['can_use_website_value'] = 0;
}
$field = $fieldset->addField($id, $fieldType, $elementFieldData);
$this->_prepareFieldOriginalData($field, $element);

if (isset($element->validate)) {
Expand Down Expand Up @@ -629,6 +638,17 @@ public function getScope()
return $scope;
}

/**
* Returns true if element was overwritten by ENV variable
*/
public function isOverwrittenByEnvVariable(string $path): bool
{
/** @var Mage_Core_Helper_EnvironmentConfigLoader $environmentConfigLoaderHelper */
$environmentConfigLoaderHelper = Mage::helper('core/environmentConfigLoader');
$path = $this->getScope() . '/' . $path;
return $environmentConfigLoaderHelper->hasPath($path);
}

/**
* Retrieve label for scope
*
Expand Down
7 changes: 7 additions & 0 deletions app/code/core/Mage/Adminhtml/Model/Config/Data.php
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,13 @@ protected function _getPathConfig($path, $full = true)
$config[$data->getPath()] = $data->getValue();
}
}

if (!$full) {
/** @var Mage_Core_Helper_EnvironmentConfigLoader $environmentConfigLoaderHelper */
$environmentConfigLoaderHelper = Mage::helper('core/environmentConfigLoader');
$envConfig = $environmentConfigLoaderHelper->getAsArray($this->getScope());
$config = array_merge($config, $envConfig);
}
return $config;
}

Expand Down
135 changes: 127 additions & 8 deletions app/code/core/Mage/Core/Helper/EnvironmentConfigLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
class Mage_Core_Helper_EnvironmentConfigLoader extends Mage_Core_Helper_Abstract
{
protected const ENV_STARTS_WITH = 'OPENMAGE_CONFIG';
protected const ENV_FEATURE_ENABLED = 'OPENMAGE_CONFIG_OVERRIDE_ALLOWED';
protected const ENV_KEY_SEPARATOR = '__';
protected const CONFIG_KEY_DEFAULT = 'DEFAULT';
protected const CONFIG_KEY_WEBSITES = 'WEBSITES';
Expand Down Expand Up @@ -57,6 +58,10 @@ class Mage_Core_Helper_EnvironmentConfigLoader extends Mage_Core_Helper_Abstract
*/
public function overrideEnvironment(Varien_Simplexml_Config $xmlConfig)
{
$data = Mage::registry('current_env_config');
if ($data) {
return;
}
$env = $this->getEnv();

foreach ($env as $configKey => $value) {
Expand All @@ -70,18 +75,116 @@ public function overrideEnvironment(Varien_Simplexml_Config $xmlConfig)
case static::CONFIG_KEY_DEFAULT:
list($unused1, $unused2, $section, $group, $field) = $configKeyParts;
$path = $this->buildPath($section, $group, $field);
$xmlConfig->setNode($this->buildNodePath($scope, $path), $value);
$nodePath = $this->buildNodePath($scope, $path);
$xmlConfig->setNode($nodePath, $value);
try {
foreach (['0', 'admin'] as $store) {
$store = Mage::app()->getStore($store);
$this->setCache($store, $value, $path);
}
} catch (Throwable $exception) {
// invalid store, intentionally empty
}
break;

case static::CONFIG_KEY_WEBSITES:
case static::CONFIG_KEY_STORES:
list($unused1, $unused2, $code, $section, $group, $field) = $configKeyParts;
list($unused1, $unused2, $storeCode, $section, $group, $field) = $configKeyParts;
$path = $this->buildPath($section, $group, $field);
$nodePath = sprintf('%s/%s/%s', strtolower($scope), strtolower($code), $path);
$storeCode = strtolower($storeCode);
$scope = strtolower($scope);
$nodePath = sprintf('%s/%s/%s', $scope, $storeCode, $path);
$xmlConfig->setNode($nodePath, $value);
try {
if (!str_contains($nodePath, 'websites')) {
foreach ([$storeCode, 'admin'] as $store) {
$store = Mage::app()->getStore($store);
$this->setCache($store, $value, $path);
}
}
} catch (Throwable $exception) {
// invalid store, intentionally empty
}
break;
}
}
Mage::register('current_env_config', true, true);
}

public function hasPath(string $wantedPath): bool
{
$data = Mage::registry("config_env_has_path_$wantedPath");
if ($data !== null) {
return $data;
}
$env = $this->getEnv();
$config = [];

foreach ($env as $configKey => $value) {
if (!$this->isConfigKeyValid($configKey)) {
continue;
}

list($configKeyParts, $scope) = $this->getConfigKey($configKey);

switch ($scope) {
case static::CONFIG_KEY_DEFAULT:
list($unused1, $unused2, $section, $group, $field) = $configKeyParts;
$path = $this->buildPath($section, $group, $field);
$nodePath = $this->buildNodePath($scope, $path);
$config[$nodePath] = $value;
break;

case static::CONFIG_KEY_WEBSITES:
case static::CONFIG_KEY_STORES:
list($unused1, $unused2, $storeCode, $section, $group, $field) = $configKeyParts;
$path = $this->buildPath($section, $group, $field);
$nodePath = $this->buildNodePath($scope, $path);
$config[$nodePath] = $value;
break;
}
}
$hasConfig = array_key_exists($wantedPath, $config);
Mage::register("config_env_has_path_$wantedPath", $hasConfig);
return $hasConfig;
}

public function getAsArray(string $wantedScope): array
{
$data = Mage::registry("config_env_array_$wantedScope");
if ($data !== null) {
return $data;
}
$env = $this->getEnv();
$config = [];

foreach ($env as $configKey => $value) {
if (!$this->isConfigKeyValid($configKey)) {
continue;
}

list($configKeyParts, $scope) = $this->getConfigKey($configKey);
if (strtolower($scope) !== strtolower($wantedScope)) {
continue;
}

switch ($scope) {
case static::CONFIG_KEY_DEFAULT:
list($unused1, $unused2, $section, $group, $field) = $configKeyParts;
$path = $this->buildPath($section, $group, $field);
$config[$path] = $value;
break;

case static::CONFIG_KEY_WEBSITES:
case static::CONFIG_KEY_STORES:
list($unused1, $unused2, $storeCode, $section, $group, $field) = $configKeyParts;
$path = $this->buildPath($section, $group, $field);
$config[$path] = $value;
break;
}
}
Mage::register("config_env_array_$wantedScope", $config);
return $config;
}

/**
Expand All @@ -95,11 +198,31 @@ public function setEnvStore(array $envStorage): void
public function getEnv(): array
{
if (empty($this->envStore)) {
$this->envStore = getenv();
$env = getenv();
$env = array_filter($env, function ($key) {
return str_starts_with($key, static::ENV_STARTS_WITH);
}, ARRAY_FILTER_USE_KEY);
$this->envStore = $env;
}
if (!isset($this->envStore[static::ENV_FEATURE_ENABLED]) ||
(bool) $this->envStore[static::ENV_FEATURE_ENABLED] === false
) {
$this->envStore = [];
return $this->envStore;
}
return $this->envStore;
}

protected function setCache(Mage_Core_Model_Store $store, $value, string $path): void
{
$refObject = new ReflectionObject($store);
$refProperty = $refObject->getProperty('_configCache');
$refProperty->setAccessible(true);
$configCache = $refProperty->getValue($store);
$configCache[$path] = $value;
$refProperty->setValue($store, $configCache);
}

protected function getConfigKey(string $configKey): array
{
$configKeyParts = array_filter(
Expand All @@ -115,10 +238,6 @@ protected function getConfigKey(string $configKey): array

protected function isConfigKeyValid(string $configKey): bool
{
if (!str_starts_with($configKey, static::ENV_STARTS_WITH)) {
return false;
}

$sectionGroupFieldRegexp = sprintf('([%s]*)', implode('', static::ALLOWED_CHARS));
$allowedChars = sprintf('[%s]', implode('', static::ALLOWED_CHARS));
$regexp = '/' . static::ENV_STARTS_WITH . static::ENV_KEY_SEPARATOR . '(WEBSITES' . static::ENV_KEY_SEPARATOR
Expand Down
1 change: 1 addition & 0 deletions app/code/core/Mage/Core/Model/App.php
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,7 @@ public function reinitStores()
*/
protected function _initStores()
{
Mage::unregister('current_env_config');
$this->_stores = [];
$this->_groups = [];
$this->_website = null;
Expand Down
3 changes: 3 additions & 0 deletions app/code/core/Mage/Core/Model/Store.php
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,9 @@ public function getConfig($path)
}

$config = Mage::getConfig();
/** @var Mage_Core_Helper_EnvironmentConfigLoader $environmentConfigLoaderHelper */
$environmentConfigLoaderHelper = Mage::helper('core/environmentConfigLoader');
$environmentConfigLoaderHelper->overrideEnvironment($config);

$fullPath = 'stores/' . $this->getCode() . '/' . $path;
$data = $config->getNode($fullPath);
Expand Down
Loading
Loading