diff --git a/lib/private/AppConfig.php b/lib/private/AppConfig.php index 5d753a6ee9ca9..c72a407383205 100644 --- a/lib/private/AppConfig.php +++ b/lib/private/AppConfig.php @@ -211,7 +211,7 @@ public function isLazy(string $app, string $key): bool { * @param string $prefix config keys prefix to search * @param bool $filtered TRUE to hide sensitive config values. Value are replaced by {@see IConfig::SENSITIVE_VALUE} * - * @return array [configKey => configValue] + * @return array [configKey => configValue] * @since 29.0.0 */ public function getAllValues(string $app, string $prefix = '', bool $filtered = false): array { @@ -219,8 +219,9 @@ public function getAllValues(string $app, string $prefix = '', bool $filtered = // if we want to filter values, we need to get sensitivity $this->loadConfigAll(); // array_merge() will remove numeric keys (here config keys), so addition arrays instead + $values = $this->formatAppValues($app, ($this->fastCache[$app] ?? []) + ($this->lazyCache[$app] ?? [])); $values = array_filter( - (($this->fastCache[$app] ?? []) + ($this->lazyCache[$app] ?? [])), + $values, function (string $key) use ($prefix): bool { return str_starts_with($key, $prefix); // filter values based on $prefix }, ARRAY_FILTER_USE_KEY @@ -253,14 +254,14 @@ function (string $key) use ($prefix): bool { * * @param string $key config key * @param bool $lazy search within lazy loaded config + * @param int|null $typedAs enforce type for the returned values ({@see self::VALUE_STRING} and others) * - * @return array [appId => configValue] + * @return array [appId => configValue] * @since 29.0.0 */ - public function searchValues(string $key, bool $lazy = false): array { + public function searchValues(string $key, bool $lazy = false, ?int $typedAs = null): array { $this->assertParams('', $key, true); $this->loadConfig($lazy); - $values = []; /** @var array> $cache */ if ($lazy) { @@ -269,9 +270,10 @@ public function searchValues(string $key, bool $lazy = false): array { $cache = $this->fastCache; } + $values = []; foreach (array_keys($cache) as $app) { if (isset($cache[$app][$key])) { - $values[$app] = $cache[$app][$key]; + $values[$app] = $this->convertTypedValue($cache[$app][$key], $typedAs ?? $this->getValueType((string)$app, $key, $lazy)); } } @@ -510,9 +512,9 @@ private function getTypedValue( * @see VALUE_BOOL * @see VALUE_ARRAY */ - public function getValueType(string $app, string $key): int { + public function getValueType(string $app, string $key, ?bool $lazy = null): int { $this->assertParams($app, $key); - $this->loadConfigAll(); + $this->loadConfig($lazy); if (!isset($this->valueTypes[$app][$key])) { throw new AppConfigUnknownKeyException('unknown config key'); @@ -1369,7 +1371,7 @@ public function getValues($app, $key) { $key = ($key === false) ? '' : $key; if (!$app) { - return $this->searchValues($key); + return $this->searchValues($key, false, self::VALUE_MIXED); } else { return $this->getAllValues($app, $key); } @@ -1387,6 +1389,58 @@ public function getFilteredValues($app) { return $this->getAllValues($app, filtered: true); } + + /** + * **Warning:** avoid default NULL value for $lazy as this will + * load all lazy values from the database + * + * @param string $app + * @param array $values ['key' => 'value'] + * @param bool|null $lazy + * + * @return array + */ + private function formatAppValues(string $app, array $values, ?bool $lazy = null): array { + foreach($values as $key => $value) { + try { + $type = $this->getValueType($app, $key, $lazy); + } catch (AppConfigUnknownKeyException $e) { + continue; + } + + $values[$key] = $this->convertTypedValue($value, $type); + } + + return $values; + } + + /** + * convert string value to the expected type + * + * @param string $value + * @param int $type + * + * @return string|int|float|bool|array + */ + private function convertTypedValue(string $value, int $type): string|int|float|bool|array { + switch ($type) { + case self::VALUE_INT: + return (int)$value; + case self::VALUE_FLOAT: + return (float)$value; + case self::VALUE_BOOL: + return in_array(strtolower($value), ['1', 'true', 'yes', 'on']); + case self::VALUE_ARRAY: + try { + return json_decode($value, true, flags: JSON_THROW_ON_ERROR); + } catch (JsonException $e) { + // ignoreable + } + break; + } + return $value; + } + /** * @param string $app * diff --git a/lib/private/AppFramework/Services/AppConfig.php b/lib/private/AppFramework/Services/AppConfig.php index 1d18baef9ed38..d3dfd3d362b08 100644 --- a/lib/private/AppFramework/Services/AppConfig.php +++ b/lib/private/AppFramework/Services/AppConfig.php @@ -97,7 +97,7 @@ public function isLazy(string $key): bool { * @param string $key config keys prefix to search * @param bool $filtered TRUE to hide sensitive config values. Value are replaced by {@see IConfig::SENSITIVE_VALUE} * - * @return array [configKey => configValue] + * @return array [configKey => configValue] * @since 29.0.0 */ public function getAllAppValues(string $key = '', bool $filtered = false): array { diff --git a/lib/public/AppFramework/Services/IAppConfig.php b/lib/public/AppFramework/Services/IAppConfig.php index 9340fdd3c321d..74588ef2c99b0 100644 --- a/lib/public/AppFramework/Services/IAppConfig.php +++ b/lib/public/AppFramework/Services/IAppConfig.php @@ -88,7 +88,7 @@ public function isLazy(string $key): bool; * @param string $key config keys prefix to search, can be empty. * @param bool $filtered filter sensitive config values * - * @return array [configKey => configValue] + * @return array [configKey => configValue] * @since 29.0.0 */ public function getAllAppValues(string $key = '', bool $filtered = false): array; diff --git a/lib/public/IAppConfig.php b/lib/public/IAppConfig.php index afcdf67f92c8c..10fc7c9065046 100644 --- a/lib/public/IAppConfig.php +++ b/lib/public/IAppConfig.php @@ -140,7 +140,7 @@ public function isLazy(string $app, string $key): bool; * @param string $prefix config keys prefix to search, can be empty. * @param bool $filtered filter sensitive config values * - * @return array [configKey => configValue] + * @return array [configKey => configValue] * @since 29.0.0 */ public function getAllValues(string $app, string $prefix = '', bool $filtered = false): array; @@ -151,11 +151,12 @@ public function getAllValues(string $app, string $prefix = '', bool $filtered = * * @param string $key config key * @param bool $lazy search within lazy loaded config + * @param int|null $typedAs enforce type for the returned values {@see self::VALUE_STRING} and others * * @return array [appId => configValue] * @since 29.0.0 */ - public function searchValues(string $key, bool $lazy = false): array; + public function searchValues(string $key, bool $lazy = false, ?int $typedAs = null): array; /** * Get config value assigned to a config key. @@ -261,9 +262,11 @@ public function getValueArray(string $app, string $key, array $default = [], boo * returns the type of config value * * **WARNING:** ignore lazy filtering, all config values are loaded from database + * unless lazy is set to false * * @param string $app id of the app * @param string $key config key + * @param bool|null $lazy * * @return int * @throws AppConfigUnknownKeyException @@ -274,7 +277,7 @@ public function getValueArray(string $app, string $key, array $default = [], boo * @see VALUE_BOOL * @see VALUE_ARRAY */ - public function getValueType(string $app, string $key): int; + public function getValueType(string $app, string $key, ?bool $lazy = null): int; /** * Store a config key and its value in database diff --git a/tests/lib/AppConfigTest.php b/tests/lib/AppConfigTest.php index 86bd339bc7ef9..5bbc3f56791ea 100644 --- a/tests/lib/AppConfigTest.php +++ b/tests/lib/AppConfigTest.php @@ -386,6 +386,21 @@ public function testIsLazyOnUnknownAppThrowsException(): void { $config->isLazy('unknown-app', 'inexistant-key'); } + public function testGetAllValues(): void { + $config = $this->generateAppConfig(); + $this->assertEquals( + [ + 'array' => ['test' => 1], + 'bool' => true, + 'float' => 3.14, + 'int' => 42, + 'mixed' => 'mix', + 'string' => 'value', + ], + $config->getAllValues('typed') + ); + } + public function testGetAllValuesWithEmptyApp(): void { $config = $this->generateAppConfig(); $this->expectException(InvalidArgumentException::class);