diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/private/AppConfig.php | 34 | ||||
-rw-r--r-- | lib/private/Config/UserConfig.php | 41 | ||||
-rw-r--r-- | lib/unstable/Config/Lexicon/ConfigLexiconEntry.php | 45 |
3 files changed, 96 insertions, 24 deletions
diff --git a/lib/private/AppConfig.php b/lib/private/AppConfig.php index b6412b410bb..976c33a9644 100644 --- a/lib/private/AppConfig.php +++ b/lib/private/AppConfig.php @@ -438,7 +438,8 @@ class AppConfig implements IAppConfig { ): string { $this->assertParams($app, $key, valueType: $type); $origKey = $key; - if (!$this->matchAndApplyLexiconDefinition($app, $key, $lazy, $type, $default)) { + /** @var ConfigLexiconEntry $lexiconEntry */ + if (!$this->matchAndApplyLexiconDefinition($app, $key, $lazy, $type, $default, lexiconEntry: $lexiconEntry)) { return $default; // returns default if strictness of lexicon is set to WARNING (block and report) } $this->loadConfig($app, $lazy); @@ -469,6 +470,13 @@ class AppConfig implements IAppConfig { } elseif (isset($this->fastCache[$app][$key])) { $value = $this->fastCache[$app][$key]; } else { + // unknown value, might want to execute something instead of just returning default. + // default value will be stored in database, unless false is returned + if (($lexiconEntry?->executeOnInit() !== null) + && $lexiconEntry->executeOnInit()($default) !== false) { + $this->setTypedValue($app, $key, $default, $lazy, $type); + } + return $default; } @@ -748,11 +756,18 @@ class AppConfig implements IAppConfig { int $type, ): bool { $this->assertParams($app, $key); - if (!$this->matchAndApplyLexiconDefinition($app, $key, $lazy, $type)) { + /** @var ConfigLexiconEntry $lexiconEntry */ + if (!$this->matchAndApplyLexiconDefinition($app, $key, $lazy, $type, lexiconEntry: $lexiconEntry)) { return false; // returns false as database is not updated } $this->loadConfig(null, $lazy); + // might want to execute something before storing new value + // will cancel storing of new value in database if false is returned + if ($lexiconEntry?->executeOnSet() !== null && $lexiconEntry?->executeOnSet()($value) === false) { + return false; + } + $sensitive = $this->isTyped(self::VALUE_SENSITIVE, $type); $inserted = $refreshCache = false; @@ -1593,6 +1608,7 @@ class AppConfig implements IAppConfig { ?bool &$lazy = null, int &$type = self::VALUE_MIXED, string &$default = '', + ?ConfigLexiconEntry &$lexiconEntry = null, ): bool { if (in_array($key, [ @@ -1617,23 +1633,23 @@ class AppConfig implements IAppConfig { return true; } - /** @var ConfigLexiconEntry $configValue */ - $configValue = $configDetails['entries'][$key]; + /** @var ConfigLexiconEntry $lexiconEntry */ + $lexiconEntry = $configDetails['entries'][$key]; $type &= ~self::VALUE_SENSITIVE; - $appConfigValueType = $configValue->getValueType()->toAppConfigFlag(); + $appConfigValueType = $lexiconEntry->getValueType()->toAppConfigFlag(); if ($type === self::VALUE_MIXED) { $type = $appConfigValueType; // we overwrite if value was requested as mixed } elseif ($appConfigValueType !== $type) { throw new AppConfigTypeConflictException('The app config key ' . $app . '/' . $key . ' is typed incorrectly in relation to the config lexicon'); } - $lazy = $configValue->isLazy(); - $default = $configValue->getDefault() ?? $default; // default from Lexicon got priority - if ($configValue->isFlagged(self::FLAG_SENSITIVE)) { + $lazy = $lexiconEntry->isLazy(); + $default = $lexiconEntry->getDefault() ?? $default; // default from Lexicon got priority + if ($lexiconEntry->isFlagged(self::FLAG_SENSITIVE)) { $type |= self::VALUE_SENSITIVE; } - if ($configValue->isDeprecated()) { + if ($lexiconEntry->isDeprecated()) { $this->logger->notice('App config key ' . $app . '/' . $key . ' is set as deprecated.'); } diff --git a/lib/private/Config/UserConfig.php b/lib/private/Config/UserConfig.php index f8c59a13d3d..f1418124fbd 100644 --- a/lib/private/Config/UserConfig.php +++ b/lib/private/Config/UserConfig.php @@ -721,7 +721,8 @@ class UserConfig implements IUserConfig { ): string { $this->assertParams($userId, $app, $key); $origKey = $key; - if (!$this->matchAndApplyLexiconDefinition($userId, $app, $key, $lazy, $type, default: $default)) { + /** @var ConfigLexiconEntry $lexiconEntry */ + if (!$this->matchAndApplyLexiconDefinition($userId, $app, $key, $lazy, $type, default: $default, lexiconEntry: $lexiconEntry)) { // returns default if strictness of lexicon is set to WARNING (block and report) return $default; } @@ -753,6 +754,13 @@ class UserConfig implements IUserConfig { } elseif (isset($this->fastCache[$userId][$app][$key])) { $value = $this->fastCache[$userId][$app][$key]; } else { + // unknown value, might want to execute something instead of just returning default. + // default value will be stored in database, unless false is returned + if (($lexiconEntry?->executeOnInit() !== null) + && $lexiconEntry->executeOnInit()($default) !== false) { + $this->setTypedValue($userId, $app, $key, $default, $lazy, 0, $type); + } + return $default; } @@ -1067,18 +1075,20 @@ class UserConfig implements IUserConfig { int $flags, ValueType $type, ): bool { - // Primary email addresses are always(!) expected to be lowercase - if ($app === 'settings' && $key === 'email') { - $value = strtolower($value); - } - $this->assertParams($userId, $app, $key); - if (!$this->matchAndApplyLexiconDefinition($userId, $app, $key, $lazy, $type, $flags)) { + /** @var ConfigLexiconEntry $lexiconEntry */ + if (!$this->matchAndApplyLexiconDefinition($userId, $app, $key, $lazy, $type, $flags, lexiconEntry: $lexiconEntry)) { // returns false as database is not updated return false; } $this->loadConfig($userId, $lazy); + // might want to execute something before storing new value + // will cancel storing of new value in database if false is returned + if ($lexiconEntry?->executeOnSet() !== null && $lexiconEntry?->executeOnSet()($value) === false) { + return false; + } + $inserted = $refreshCache = false; $origValue = $value; $sensitive = $this->isFlagged(self::FLAG_SENSITIVE, $flags); @@ -1887,6 +1897,7 @@ class UserConfig implements IUserConfig { ValueType &$type = ValueType::MIXED, int &$flags = 0, string &$default = '', + ?ConfigLexiconEntry &$lexiconEntry = null, ): bool { $configDetails = $this->getConfigDetailsFromLexicon($app); if (array_key_exists($key, $configDetails['aliases']) && !$this->ignoreLexiconAliases) { @@ -1903,18 +1914,18 @@ class UserConfig implements IUserConfig { return true; } - /** @var ConfigLexiconEntry $configValue */ - $configValue = $configDetails['entries'][$key]; + /** @var ConfigLexiconEntry $lexiconEntry */ + $lexiconEntry = $configDetails['entries'][$key]; if ($type === ValueType::MIXED) { // we overwrite if value was requested as mixed - $type = $configValue->getValueType(); - } elseif ($configValue->getValueType() !== $type) { + $type = $lexiconEntry->getValueType(); + } elseif ($lexiconEntry->getValueType() !== $type) { throw new TypeConflictException('The user config key ' . $app . '/' . $key . ' is typed incorrectly in relation to the config lexicon'); } - $lazy = $configValue->isLazy(); - $flags = $configValue->getFlags(); - if ($configValue->isDeprecated()) { + $lazy = $lexiconEntry->isLazy(); + $flags = $lexiconEntry->getFlags(); + if ($lexiconEntry->isDeprecated()) { $this->logger->notice('User config key ' . $app . '/' . $key . ' is set as deprecated.'); } @@ -1925,7 +1936,7 @@ class UserConfig implements IUserConfig { } // default from Lexicon got priority but it can still be overwritten by admin - $default = $this->getSystemDefault($app, $configValue) ?? $configValue->getDefault() ?? $default; + $default = $this->getSystemDefault($app, $lexiconEntry) ?? $lexiconEntry->getDefault() ?? $default; // returning false will make get() returning $default and set() not changing value in database return !$enforcedValue; diff --git a/lib/unstable/Config/Lexicon/ConfigLexiconEntry.php b/lib/unstable/Config/Lexicon/ConfigLexiconEntry.php index d0d9b4cbd23..d63d4aafe46 100644 --- a/lib/unstable/Config/Lexicon/ConfigLexiconEntry.php +++ b/lib/unstable/Config/Lexicon/ConfigLexiconEntry.php @@ -8,6 +8,7 @@ declare(strict_types=1); namespace NCU\Config\Lexicon; +use Closure; use NCU\Config\ValueType; /** @@ -22,6 +23,8 @@ class ConfigLexiconEntry { private string $definition = ''; private ?string $default = null; + private ?Closure $initialize = null; + private ?Closure $onSet = null; /** * @param string $key config key @@ -137,6 +140,48 @@ class ConfigLexiconEntry { } /** + * set a closure to be executed when reading a non-set config value + * first param of the closure is the default value of the config key. + * + * @experimental 32.0.0 + */ + public function initialize(Closure $closure): self { + $this->initialize = $closure; + return $this; + } + + /** + * returns if something needs to be executed when reading a non-set config value + * + * @return Closure|null NULL if nothing is supposed to happens + * @experimental 32.0.0 + */ + public function executeOnInit(): ?Closure { + return $this->initialize; + } + + /** + * set a closure to be executed when setting a value to this config key + * first param of the closure is future value. + * + * @experimental 32.0.0 + */ + public function onSet(Closure $closure): self { + $this->onSet = $closure; + return $this; + } + + /** + * returns if something needs to be executed when writing a new value + * + * @return Closure|null NULL if nothing is supposed to happens + * @experimental 32.0.0 + */ + public function executeOnSet(): ?Closure { + return $this->onSet; + } + + /** * convert $entry into string, based on the expected type for config value * * @param string|int|float|bool|array $entry |