Skip to content
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: Fix/environment loader #4617

Open
wants to merge 23 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
3ff61d7
fix: set cache when env loader overrides data
Dec 29, 2024
b8bc6bf
feat?: call env helper on config get
Feb 8, 2025
a5b3660
feat?: backend: show data from env
Feb 8, 2025
9818a2e
feat?: backend: disable field when ENV data is available
Feb 8, 2025
08ab039
Update app/code/core/Mage/Adminhtml/Block/System/Config/Form.php
sreichel Feb 8, 2025
9638115
Update app/code/core/Mage/Core/Helper/EnvironmentConfigLoader.php
sreichel Feb 8, 2025
dff4ecd
feat?: backend: do not log on invalid stores - creates infinite loop
Feb 9, 2025
ab792a3
feat: move env variables "str_starts_with"
Feb 17, 2025
93d4aec
feat: add env flag to disable/enable feature
Feb 17, 2025
1788e02
fix: fix tests
Feb 17, 2025
b230322
feat: set disabled, set scope label
Feb 17, 2025
008464f
feat: remove checkbox to override
Feb 17, 2025
30ceac1
chore: remove inline helper variable name
Feb 17, 2025
7b76e89
Update tests/unit/Mage/Core/Helper/EnvironmentConfigLoaderTest.php
pquerner Feb 17, 2025
367e397
Update tests/unit/Mage/Core/Helper/EnvironmentConfigLoaderTest.php
pquerner Feb 17, 2025
cabcd7d
Update app/code/core/Mage/Core/Helper/EnvironmentConfigLoader.php
pquerner Feb 17, 2025
694b06e
Update app/code/core/Mage/Adminhtml/Block/System/Config/Form.php
pquerner Feb 17, 2025
966ca28
Update tests/unit/Mage/Core/Helper/EnvironmentConfigLoaderTest.php
pquerner Feb 17, 2025
0bbe3d5
Update app/code/core/Mage/Adminhtml/Block/System/Config/Form.php
pquerner Feb 18, 2025
da68a14
feat: add "hasPath" test
Feb 18, 2025
8b4fb87
feat: add "asArray" test
Feb 18, 2025
de18a5d
tests: add test cases
Feb 18, 2025
08756c9
Merge branch 'main' into fix/environmentLoader
sreichel Feb 25, 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
133 changes: 125 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,29 @@ 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])) {
$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 +236,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
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