From 0f3e4255ca140c1cf8ff717b6804fe00a8d429e3 Mon Sep 17 00:00:00 2001 From: Philipp Date: Sun, 4 Oct 2020 20:37:35 +0200 Subject: [PATCH] Introduce Config\Cache Source indicators (File, DB, Server Env) --- src/Core/Config/Cache.php | 70 ++++++++++++++++------------ src/Core/Config/JitConfig.php | 2 +- src/Core/Config/PreloadConfig.php | 2 +- src/Util/ConfigFileLoader.php | 12 ++--- tests/src/Core/Config/CacheTest.php | 9 ++-- tests/src/Core/Config/ConfigTest.php | 6 +-- 6 files changed, 56 insertions(+), 45 deletions(-) diff --git a/src/Core/Config/Cache.php b/src/Core/Config/Cache.php index b3fe9d4e00..b78b57f57d 100644 --- a/src/Core/Config/Cache.php +++ b/src/Core/Config/Cache.php @@ -30,11 +30,26 @@ use ParagonIE\HiddenString\HiddenString; */ class Cache { + /** @var int Indicates that the cache entry is set by file - Low Priority */ + const SOURCE_FILE = 0; + /** @var int Indicates that the cache entry is set by the DB config table - Middle Priority */ + const SOURCE_DB = 1; + /** @var int Indicates that the cache entry is set by a server environment variable - High Priority */ + const SOURCE_ENV = 3; + + /** @var int Default value for a config source */ + const SOURCE_DEFAULT = self::SOURCE_FILE; + /** * @var array */ private $config; + /** + * @var int[][] + */ + private $source = []; + /** * @var bool */ @@ -43,11 +58,12 @@ class Cache /** * @param array $config A initial config array * @param bool $hidePasswordOutput True, if cache variables should take extra care of password values + * @param int $source Sets a source of the initial config values */ - public function __construct(array $config = [], bool $hidePasswordOutput = true) + public function __construct(array $config = [], bool $hidePasswordOutput = true, $source = self::SOURCE_DEFAULT) { $this->hidePasswordOutput = $hidePasswordOutput; - $this->load($config); + $this->load($config, $source); } /** @@ -55,9 +71,9 @@ class Cache * Doesn't overwrite previously set values by default to prevent default config files to supersede DB Config. * * @param array $config - * @param bool $overwrite Force value overwrite if the config key already exists + * @param int $source Indicates the source of the config entry */ - public function load(array $config, bool $overwrite = false) + public function load(array $config, int $source = self::SOURCE_DEFAULT) { $categories = array_keys($config); @@ -68,11 +84,7 @@ class Cache foreach ($keys as $key) { $value = $config[$category][$key]; if (isset($value)) { - if ($overwrite) { - $this->set($category, $key, $value); - } else { - $this->setDefault($category, $key, $value); - } + $this->set($category, $key, $value, $source); } } } @@ -91,49 +103,45 @@ class Cache { if (isset($this->config[$cat][$key])) { return $this->config[$cat][$key]; - } elseif (!isset($key) && isset($this->config[$cat])) { + } else if (!isset($key) && isset($this->config[$cat])) { return $this->config[$cat]; } else { return null; } } - /** - * Sets a default value in the config cache. Ignores already existing keys. - * - * @param string $cat Config category - * @param string $key Config key - * @param mixed $value Default value to set - */ - private function setDefault(string $cat, string $key, $value) - { - if (!isset($this->config[$cat][$key])) { - $this->set($cat, $key, $value); - } - } - /** * Sets a value in the config cache. Accepts raw output from the config table * - * @param string $cat Config category - * @param string $key Config key - * @param mixed $value Value to set + * @param string $cat Config category + * @param string $key Config key + * @param mixed $value Value to set + * @param int $source The source of the current config key * * @return bool True, if the value is set */ - public function set(string $cat, string $key, $value) + public function set(string $cat, string $key, $value, $source = self::SOURCE_DEFAULT) { if (!isset($this->config[$cat])) { $this->config[$cat] = []; + $this->source[$cat] = []; + } + + if (isset($this->source[$cat][$key]) && + $source < $this->source[$cat][$key]) { + return false; } if ($this->hidePasswordOutput && - $key == 'password' && - is_string($value)) { + $key == 'password' && + is_string($value)) { $this->config[$cat][$key] = new HiddenString((string)$value); } else { $this->config[$cat][$key] = $value; } + + $this->source[$cat][$key] = $source; + return true; } @@ -149,8 +157,10 @@ class Cache { if (isset($this->config[$cat][$key])) { unset($this->config[$cat][$key]); + unset($this->source[$cat][$key]); if (count($this->config[$cat]) == 0) { unset($this->config[$cat]); + unset($this->source[$cat]); } return true; } else { diff --git a/src/Core/Config/JitConfig.php b/src/Core/Config/JitConfig.php index 4cf0d06f36..dbf1ea3eaf 100644 --- a/src/Core/Config/JitConfig.php +++ b/src/Core/Config/JitConfig.php @@ -70,7 +70,7 @@ class JitConfig extends BaseConfig } // load the whole category out of the DB into the cache - $this->configCache->load($config, true); + $this->configCache->load($config, Cache::SOURCE_DB); } /** diff --git a/src/Core/Config/PreloadConfig.php b/src/Core/Config/PreloadConfig.php index c1181414ba..168823f4dd 100644 --- a/src/Core/Config/PreloadConfig.php +++ b/src/Core/Config/PreloadConfig.php @@ -69,7 +69,7 @@ class PreloadConfig extends BaseConfig $this->config_loaded = true; // load the whole category out of the DB into the cache - $this->configCache->load($config, true); + $this->configCache->load($config, Cache::SOURCE_DB); } /** diff --git a/src/Util/ConfigFileLoader.php b/src/Util/ConfigFileLoader.php index fc6685946c..54c2ebe0c0 100644 --- a/src/Util/ConfigFileLoader.php +++ b/src/Util/ConfigFileLoader.php @@ -104,12 +104,12 @@ class ConfigFileLoader public function setupCache(Cache $config, $raw = false) { // Load static config files first, the order is important - $config->load($this->loadStaticConfig('defaults')); - $config->load($this->loadStaticConfig('settings')); + $config->load($this->loadStaticConfig('defaults'), Cache::SOURCE_FILE); + $config->load($this->loadStaticConfig('settings'), Cache::SOURCE_FILE); // try to load the legacy config first - $config->load($this->loadLegacyConfig('htpreconfig'), true); - $config->load($this->loadLegacyConfig('htconfig'), true); + $config->load($this->loadLegacyConfig('htpreconfig'), Cache::SOURCE_FILE); + $config->load($this->loadLegacyConfig('htconfig'), Cache::SOURCE_FILE); // Now load every other config you find inside the 'config/' directory $this->loadCoreConfig($config); @@ -157,12 +157,12 @@ class ConfigFileLoader { // try to load legacy ini-files first foreach ($this->getConfigFiles(true) as $configFile) { - $config->load($this->loadINIConfigFile($configFile), true); + $config->load($this->loadINIConfigFile($configFile), Cache::SOURCE_FILE); } // try to load supported config at last to overwrite it foreach ($this->getConfigFiles() as $configFile) { - $config->load($this->loadConfigFile($configFile), true); + $config->load($this->loadConfigFile($configFile), Cache::SOURCE_FILE); } return []; diff --git a/tests/src/Core/Config/CacheTest.php b/tests/src/Core/Config/CacheTest.php index c4e59e6914..02b98c7ec1 100644 --- a/tests/src/Core/Config/CacheTest.php +++ b/tests/src/Core/Config/CacheTest.php @@ -83,13 +83,14 @@ class CacheTest extends MockedTest ]; $configCache = new Cache(); - $configCache->load($data); - $configCache->load($override); + $configCache->load($data, Cache::SOURCE_DB); + // doesn't override - Low Priority due Config file + $configCache->load($override, Cache::SOURCE_FILE); $this->assertConfigValues($data, $configCache); - // override the value - $configCache->load($override, true); + // override the value - High Prio due Server Env + $configCache->load($override, Cache::SOURCE_ENV); $this->assertEquals($override['system']['test'], $configCache->get('system', 'test')); $this->assertEquals($override['system']['boolTrue'], $configCache->get('system', 'boolTrue')); diff --git a/tests/src/Core/Config/ConfigTest.php b/tests/src/Core/Config/ConfigTest.php index 7dd61d4518..48df2b2a4a 100644 --- a/tests/src/Core/Config/ConfigTest.php +++ b/tests/src/Core/Config/ConfigTest.php @@ -350,7 +350,7 @@ abstract class ConfigTest extends MockedTest */ public function testGetWithRefresh($data) { - $this->configCache->load(['test' => ['it' => 'now']]); + $this->configCache->load(['test' => ['it' => 'now']], Cache::SOURCE_FILE); $this->testedConfig = $this->getInstance(); $this->assertInstanceOf(Cache::class, $this->testedConfig->getCache()); @@ -375,7 +375,7 @@ abstract class ConfigTest extends MockedTest */ public function testDeleteWithoutDB($data) { - $this->configCache->load(['test' => ['it' => $data]]); + $this->configCache->load(['test' => ['it' => $data]], Cache::SOURCE_FILE); $this->testedConfig = $this->getInstance(); $this->assertInstanceOf(Cache::class, $this->testedConfig->getCache()); @@ -395,7 +395,7 @@ abstract class ConfigTest extends MockedTest */ public function testDeleteWithDB() { - $this->configCache->load(['test' => ['it' => 'now', 'quarter' => 'true']]); + $this->configCache->load(['test' => ['it' => 'now', 'quarter' => 'true']], Cache::SOURCE_FILE); $this->configModel->shouldReceive('delete') ->with('test', 'it')