From 7c04818c5c078fb1dc7c5b79f295fc40a60a6296 Mon Sep 17 00:00:00 2001 From: Maxence Lange Date: Mon, 21 Oct 2024 18:31:14 -0100 Subject: [PATCH] feat(user-prefs): iterator instead of array on search Signed-off-by: Maxence Lange --- .../Version31000Date20240814184402.php | 2 +- lib/composer/composer/autoload_classmap.php | 14 ++- lib/composer/composer/autoload_static.php | 14 ++- lib/private/AllConfig.php | 15 +-- lib/private/{ => Config}/UserPreferences.php | 102 +++++++----------- lib/private/Server.php | 4 +- .../Exceptions/IncorrectTypeException.php} | 4 +- .../Exceptions/TypeConflictException.php | 6 +- .../Exceptions/UnknownKeyException.php | 6 +- .../IUserPreferences.php | 40 +++++-- .../{UserPreferences => Config}/ValueType.php | 9 +- lib/public/IConfig.php | 2 +- .../Exceptions/IncorrectTypeException.php | 15 --- tests/lib/UserPreferencesTest.php | 20 ++-- 14 files changed, 114 insertions(+), 139 deletions(-) rename lib/private/{ => Config}/UserPreferences.php (94%) rename lib/public/{UserPreferences/Exceptions/UserPreferencesException.php => Config/Exceptions/IncorrectTypeException.php} (68%) rename lib/public/{UserPreferences => Config}/Exceptions/TypeConflictException.php (64%) rename lib/public/{UserPreferences => Config}/Exceptions/UnknownKeyException.php (64%) rename lib/public/{UserPreferences => Config}/IUserPreferences.php (95%) rename lib/public/{UserPreferences => Config}/ValueType.php (87%) delete mode 100644 lib/public/UserPreferences/Exceptions/IncorrectTypeException.php diff --git a/core/Migrations/Version31000Date20240814184402.php b/core/Migrations/Version31000Date20240814184402.php index 87b7e93db97..14b32a704be 100644 --- a/core/Migrations/Version31000Date20240814184402.php +++ b/core/Migrations/Version31000Date20240814184402.php @@ -38,7 +38,7 @@ class Version31000Date20240814184402 extends SimpleMigrationStep { $table->addColumn('lazy', Types::SMALLINT, ['notnull' => true, 'default' => 0, 'length' => 1, 'unsigned' => true]); $table->addColumn('type', Types::SMALLINT, ['notnull' => true, 'default' => 0, 'unsigned' => true]); $table->addColumn('flags', Types::INTEGER, ['notnull' => true, 'default' => 0, 'unsigned' => true]); - $table->addColumn('indexed', Types::STRING, ['notnull' => true, 'default' => '', 'length' => 64]); + $table->addColumn('indexed', Types::STRING, ['notnull' => false, 'default' => '', 'length' => 64]); // removing this index from Version13000Date20170718121200 // $table->addIndex(['appid', 'configkey'], 'preferences_app_key'); diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index 3e65291819b..c3abaefd56c 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -223,6 +223,11 @@ return array( 'OCP\\Common\\Exception\\NotFoundException' => $baseDir . '/lib/public/Common/Exception/NotFoundException.php', 'OCP\\Config\\BeforePreferenceDeletedEvent' => $baseDir . '/lib/public/Config/BeforePreferenceDeletedEvent.php', 'OCP\\Config\\BeforePreferenceSetEvent' => $baseDir . '/lib/public/Config/BeforePreferenceSetEvent.php', + 'OCP\\Config\\Exceptions\\IncorrectTypeException' => $baseDir . '/lib/public/Config/Exceptions/IncorrectTypeException.php', + 'OCP\\Config\\Exceptions\\TypeConflictException' => $baseDir . '/lib/public/Config/Exceptions/TypeConflictException.php', + 'OCP\\Config\\Exceptions\\UnknownKeyException' => $baseDir . '/lib/public/Config/Exceptions/UnknownKeyException.php', + 'OCP\\Config\\IUserPreferences' => $baseDir . '/lib/public/Config/IUserPreferences.php', + 'OCP\\Config\\ValueType' => $baseDir . '/lib/public/Config/ValueType.php', 'OCP\\Console\\ConsoleEvent' => $baseDir . '/lib/public/Console/ConsoleEvent.php', 'OCP\\Console\\ReservedOptions' => $baseDir . '/lib/public/Console/ReservedOptions.php', 'OCP\\Constants' => $baseDir . '/lib/public/Constants.php', @@ -839,13 +844,6 @@ return array( 'OCP\\UserMigration\\ISizeEstimationMigrator' => $baseDir . '/lib/public/UserMigration/ISizeEstimationMigrator.php', 'OCP\\UserMigration\\TMigratorBasicVersionHandling' => $baseDir . '/lib/public/UserMigration/TMigratorBasicVersionHandling.php', 'OCP\\UserMigration\\UserMigrationException' => $baseDir . '/lib/public/UserMigration/UserMigrationException.php', - 'OCP\\UserPreferences\\Exceptions\\IncorrectTypeException' => $baseDir . '/lib/public/UserPreferences/Exceptions/IncorrectTypeException.php', - 'OCP\\UserPreferences\\Exceptions\\TypeConflictException' => $baseDir . '/lib/public/UserPreferences/Exceptions/TypeConflictException.php', - 'OCP\\UserPreferences\\Exceptions\\UnknownKeyException' => $baseDir . '/lib/public/UserPreferences/Exceptions/UnknownKeyException.php', - 'OCP\\UserPreferences\\Exceptions\\UserPreferencesException' => $baseDir . '/lib/public/UserPreferences/Exceptions/UserPreferencesException.php', - 'OCP\\UserPreferences\\IUserPreferences' => $baseDir . '/lib/public/UserPreferences/IUserPreferences.php', - 'OCP\\UserPreferences\\ValueType' => $baseDir . '/lib/public/UserPreferences/ValueType.php', - 'OCP\\UserPreferences\\ValueTypeDefinition' => $baseDir . '/lib/public/UserPreferences/ValueTypeDefinition.php', 'OCP\\UserStatus\\IManager' => $baseDir . '/lib/public/UserStatus/IManager.php', 'OCP\\UserStatus\\IProvider' => $baseDir . '/lib/public/UserStatus/IProvider.php', 'OCP\\UserStatus\\IUserStatus' => $baseDir . '/lib/public/UserStatus/IUserStatus.php', @@ -1125,6 +1123,7 @@ return array( 'OC\\Comments\\Manager' => $baseDir . '/lib/private/Comments/Manager.php', 'OC\\Comments\\ManagerFactory' => $baseDir . '/lib/private/Comments/ManagerFactory.php', 'OC\\Config' => $baseDir . '/lib/private/Config.php', + 'OC\\Config\\UserPreferences' => $baseDir . '/lib/private/Config/UserPreferences.php', 'OC\\Console\\Application' => $baseDir . '/lib/private/Console/Application.php', 'OC\\Console\\TimestampFormatter' => $baseDir . '/lib/private/Console/TimestampFormatter.php', 'OC\\ContactsManager' => $baseDir . '/lib/private/ContactsManager.php', @@ -2005,7 +2004,6 @@ return array( 'OC\\Updater\\Exceptions\\ReleaseMetadataException' => $baseDir . '/lib/private/Updater/Exceptions/ReleaseMetadataException.php', 'OC\\Updater\\ReleaseMetadata' => $baseDir . '/lib/private/Updater/ReleaseMetadata.php', 'OC\\Updater\\VersionCheck' => $baseDir . '/lib/private/Updater/VersionCheck.php', - 'OC\\UserPreferences' => $baseDir . '/lib/private/UserPreferences.php', 'OC\\UserStatus\\ISettableProvider' => $baseDir . '/lib/private/UserStatus/ISettableProvider.php', 'OC\\UserStatus\\Manager' => $baseDir . '/lib/private/UserStatus/Manager.php', 'OC\\User\\AvailabilityCoordinator' => $baseDir . '/lib/private/User/AvailabilityCoordinator.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index 46e59b25846..cf821ddeba0 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -264,6 +264,11 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\Common\\Exception\\NotFoundException' => __DIR__ . '/../../..' . '/lib/public/Common/Exception/NotFoundException.php', 'OCP\\Config\\BeforePreferenceDeletedEvent' => __DIR__ . '/../../..' . '/lib/public/Config/BeforePreferenceDeletedEvent.php', 'OCP\\Config\\BeforePreferenceSetEvent' => __DIR__ . '/../../..' . '/lib/public/Config/BeforePreferenceSetEvent.php', + 'OCP\\Config\\Exceptions\\IncorrectTypeException' => __DIR__ . '/../../..' . '/lib/public/Config/Exceptions/IncorrectTypeException.php', + 'OCP\\Config\\Exceptions\\TypeConflictException' => __DIR__ . '/../../..' . '/lib/public/Config/Exceptions/TypeConflictException.php', + 'OCP\\Config\\Exceptions\\UnknownKeyException' => __DIR__ . '/../../..' . '/lib/public/Config/Exceptions/UnknownKeyException.php', + 'OCP\\Config\\IUserPreferences' => __DIR__ . '/../../..' . '/lib/public/Config/IUserPreferences.php', + 'OCP\\Config\\ValueType' => __DIR__ . '/../../..' . '/lib/public/Config/ValueType.php', 'OCP\\Console\\ConsoleEvent' => __DIR__ . '/../../..' . '/lib/public/Console/ConsoleEvent.php', 'OCP\\Console\\ReservedOptions' => __DIR__ . '/../../..' . '/lib/public/Console/ReservedOptions.php', 'OCP\\Constants' => __DIR__ . '/../../..' . '/lib/public/Constants.php', @@ -880,13 +885,6 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\UserMigration\\ISizeEstimationMigrator' => __DIR__ . '/../../..' . '/lib/public/UserMigration/ISizeEstimationMigrator.php', 'OCP\\UserMigration\\TMigratorBasicVersionHandling' => __DIR__ . '/../../..' . '/lib/public/UserMigration/TMigratorBasicVersionHandling.php', 'OCP\\UserMigration\\UserMigrationException' => __DIR__ . '/../../..' . '/lib/public/UserMigration/UserMigrationException.php', - 'OCP\\UserPreferences\\Exceptions\\IncorrectTypeException' => __DIR__ . '/../../..' . '/lib/public/UserPreferences/Exceptions/IncorrectTypeException.php', - 'OCP\\UserPreferences\\Exceptions\\TypeConflictException' => __DIR__ . '/../../..' . '/lib/public/UserPreferences/Exceptions/TypeConflictException.php', - 'OCP\\UserPreferences\\Exceptions\\UnknownKeyException' => __DIR__ . '/../../..' . '/lib/public/UserPreferences/Exceptions/UnknownKeyException.php', - 'OCP\\UserPreferences\\Exceptions\\UserPreferencesException' => __DIR__ . '/../../..' . '/lib/public/UserPreferences/Exceptions/UserPreferencesException.php', - 'OCP\\UserPreferences\\IUserPreferences' => __DIR__ . '/../../..' . '/lib/public/UserPreferences/IUserPreferences.php', - 'OCP\\UserPreferences\\ValueType' => __DIR__ . '/../../..' . '/lib/public/UserPreferences/ValueType.php', - 'OCP\\UserPreferences\\ValueTypeDefinition' => __DIR__ . '/../../..' . '/lib/public/UserPreferences/ValueTypeDefinition.php', 'OCP\\UserStatus\\IManager' => __DIR__ . '/../../..' . '/lib/public/UserStatus/IManager.php', 'OCP\\UserStatus\\IProvider' => __DIR__ . '/../../..' . '/lib/public/UserStatus/IProvider.php', 'OCP\\UserStatus\\IUserStatus' => __DIR__ . '/../../..' . '/lib/public/UserStatus/IUserStatus.php', @@ -1166,6 +1164,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\Comments\\Manager' => __DIR__ . '/../../..' . '/lib/private/Comments/Manager.php', 'OC\\Comments\\ManagerFactory' => __DIR__ . '/../../..' . '/lib/private/Comments/ManagerFactory.php', 'OC\\Config' => __DIR__ . '/../../..' . '/lib/private/Config.php', + 'OC\\Config\\UserPreferences' => __DIR__ . '/../../..' . '/lib/private/Config/UserPreferences.php', 'OC\\Console\\Application' => __DIR__ . '/../../..' . '/lib/private/Console/Application.php', 'OC\\Console\\TimestampFormatter' => __DIR__ . '/../../..' . '/lib/private/Console/TimestampFormatter.php', 'OC\\ContactsManager' => __DIR__ . '/../../..' . '/lib/private/ContactsManager.php', @@ -2046,7 +2045,6 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\Updater\\Exceptions\\ReleaseMetadataException' => __DIR__ . '/../../..' . '/lib/private/Updater/Exceptions/ReleaseMetadataException.php', 'OC\\Updater\\ReleaseMetadata' => __DIR__ . '/../../..' . '/lib/private/Updater/ReleaseMetadata.php', 'OC\\Updater\\VersionCheck' => __DIR__ . '/../../..' . '/lib/private/Updater/VersionCheck.php', - 'OC\\UserPreferences' => __DIR__ . '/../../..' . '/lib/private/UserPreferences.php', 'OC\\UserStatus\\ISettableProvider' => __DIR__ . '/../../..' . '/lib/private/UserStatus/ISettableProvider.php', 'OC\\UserStatus\\Manager' => __DIR__ . '/../../..' . '/lib/private/UserStatus/Manager.php', 'OC\\User\\AvailabilityCoordinator' => __DIR__ . '/../../..' . '/lib/private/User/AvailabilityCoordinator.php', diff --git a/lib/private/AllConfig.php b/lib/private/AllConfig.php index b2ebe322d9e..8f7e5359c96 100644 --- a/lib/private/AllConfig.php +++ b/lib/private/AllConfig.php @@ -6,13 +6,14 @@ */ namespace OC; +use OC\Config\UserPreferences; use OCP\Cache\CappedMemoryCache; +use OCP\Config\Exceptions\TypeConflictException; +use OCP\Config\IUserPreferences; +use OCP\Config\ValueType; use OCP\IConfig; use OCP\IDBConnection; use OCP\PreConditionNotMetException; -use OCP\UserPreferences\Exceptions\TypeConflictException; -use OCP\UserPreferences\IUserPreferences; -use OCP\UserPreferences\ValueType; /** * Class to combine all the configuration options ownCloud offers @@ -376,11 +377,11 @@ class AllConfig implements IConfig { * @param string $appName the app to get the user for * @param string $key the key to get the user for * @param string $value the value to get the user for - * @return list of user IDs + * @return array of user IDs * @deprecated 31.0.0 - use {@see IUserPreferences::searchUsersByValueString} directly */ public function getUsersForUserValue($appName, $key, $value) { - return \OCP\Server::get(IUserPreferences::class)->searchUsersByValueDeprecated($appName, $key, $value); + return iterator_to_array(\OCP\Server::get(IUserPreferences::class)->searchUsersByValueString($appName, $key, $value)); } /** @@ -389,7 +390,7 @@ class AllConfig implements IConfig { * @param string $appName the app to get the user for * @param string $key the key to get the user for * @param string $value the value to get the user for - * @return list of user IDs + * @return array of user IDs * @deprecated 31.0.0 - use {@see IUserPreferences::searchUsersByValueString} directly */ public function getUsersForUserValueCaseInsensitive($appName, $key, $value) { @@ -397,7 +398,7 @@ class AllConfig implements IConfig { return $this->getUsersForUserValue($appName, $key, strtolower($value)); } - return \OCP\Server::get(IUserPreferences::class)->searchUsersByValueDeprecated($appName, $key, $value, true); + return iterator_to_array(\OCP\Server::get(IUserPreferences::class)->searchUsersByValueString($appName, $key, $value, true)); } public function getSystemConfig() { diff --git a/lib/private/UserPreferences.php b/lib/private/Config/UserPreferences.php similarity index 94% rename from lib/private/UserPreferences.php rename to lib/private/Config/UserPreferences.php index 22313292e94..6dd9c633836 100644 --- a/lib/private/UserPreferences.php +++ b/lib/private/Config/UserPreferences.php @@ -6,21 +6,22 @@ declare(strict_types=1); * SPDX-License-Identifier: AGPL-3.0-or-later */ -namespace OC; +namespace OC\Config; +use Generator; use InvalidArgumentException; use JsonException; +use OCP\Config\Exceptions\IncorrectTypeException; +use OCP\Config\Exceptions\TypeConflictException; +use OCP\Config\Exceptions\UnknownKeyException; +use OCP\Config\IUserPreferences; +use OCP\Config\ValueType; use OCP\DB\Exception as DBException; use OCP\DB\IResult; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\IConfig; use OCP\IDBConnection; use OCP\Security\ICrypto; -use OCP\UserPreferences\Exceptions\IncorrectTypeException; -use OCP\UserPreferences\Exceptions\TypeConflictException; -use OCP\UserPreferences\Exceptions\UnknownKeyException; -use OCP\UserPreferences\IUserPreferences; -use OCP\UserPreferences\ValueType; use Psr\Log\LoggerInterface; /** @@ -52,7 +53,7 @@ class UserPreferences implements IUserPreferences { private array $fastCache = []; // cache for normal preference keys /** @var array>> ['user_id' => ['app_id' => ['key' => 'value']]] */ private array $lazyCache = []; // cache for lazy preference keys - /** @var array|<'flags', int>> ['user_id' => ['app_id' => ['key' => ['type' => ValueType, 'flags' => bitflag]]] */ + /** @var array>>> ['user_id' => ['app_id' => ['key' => ['type' => ValueType, 'flags' => bitflag]]]] */ private array $valueDetails = []; // type for all preference values /** @var array>> ['user_id' => ['app_id' => ['key' => bitflag]]] */ private array $valueTypes = []; // type for all preference values @@ -358,7 +359,7 @@ class UserPreferences implements IUserPreferences { while ($row = $result->fetch()) { $value = $row['configvalue']; try { - $value = $this->convertTypedValue($value, $typedAs ?? ValueType::from((int) $row['type'])); + $value = $this->convertTypedValue($value, $typedAs ?? ValueType::from((int)$row['type'])); } catch (IncorrectTypeException) { } $values[$row['userid']] = $value; @@ -393,29 +394,13 @@ class UserPreferences implements IUserPreferences { * @param string $value preference value * @param bool $caseInsensitive non-case-sensitive search, only works if $value is a string * - * @return list + * @return Generator * @since 31.0.0 */ - public function searchUsersByValueString(string $app, string $key, string $value, bool $caseInsensitive = false): array { + public function searchUsersByValueString(string $app, string $key, string $value, bool $caseInsensitive = false): Generator { return $this->searchUsersByTypedValue($app, $key, $value, $caseInsensitive); } - /** - * @inheritDoc - * - * @param string $app id of the app - * @param string $key preference key - * @param string $value preference value - * @param bool $caseInsensitive non-case-sensitive search, only works if $value is a string - * @internal - * @deprecated since 31.0.0 - {@see } - * @return list - * @since 31.0.0 - */ - public function searchUsersByValueDeprecated(string $app, string $key, string $value, bool $caseInsensitive = false): array { - return $this->searchUsersByTypedValue($app, $key, $value, $caseInsensitive, true); - } - /** * @inheritDoc * @@ -423,10 +408,10 @@ class UserPreferences implements IUserPreferences { * @param string $key preference key * @param int $value preference value * - * @return list + * @return Generator * @since 31.0.0 */ - public function searchUsersByValueInt(string $app, string $key, int $value): array { + public function searchUsersByValueInt(string $app, string $key, int $value): Generator { return $this->searchUsersByValueString($app, $key, (string)$value); } @@ -437,10 +422,10 @@ class UserPreferences implements IUserPreferences { * @param string $key preference key * @param array $values list of preference values * - * @return list + * @return Generator * @since 31.0.0 */ - public function searchUsersByValues(string $app, string $key, array $values): array { + public function searchUsersByValues(string $app, string $key, array $values): Generator { return $this->searchUsersByTypedValue($app, $key, $values); } @@ -451,10 +436,10 @@ class UserPreferences implements IUserPreferences { * @param string $key preference key * @param bool $value preference value * - * @return list + * @return Generator * @since 31.0.0 */ - public function searchUsersByValueBool(string $app, string $key, bool $value): array { + public function searchUsersByValueBool(string $app, string $key, bool $value): Generator { $values = ['0', 'off', 'false', 'no']; if ($value) { $values = ['1', 'on', 'true', 'yes']; @@ -470,11 +455,10 @@ class UserPreferences implements IUserPreferences { * @param string $key * @param string|array $value * @param bool $caseInsensitive - * @param bool $withinNotIndexedField DEPRECATED: should only be used to stay compatible with not-indexed/pre-31 preferences value * - * @return list + * @return Generator */ - private function searchUsersByTypedValue(string $app, string $key, string|array $value, bool $caseInsensitive = false): array { + private function searchUsersByTypedValue(string $app, string $key, string|array $value, bool $caseInsensitive = false): Generator { $this->assertParams('', $app, $key, allowEmptyUser: true); $qb = $this->connection->getQueryBuilder(); @@ -483,14 +467,14 @@ class UserPreferences implements IUserPreferences { $qb->where($qb->expr()->eq('appid', $qb->createNamedParameter($app))); $qb->andWhere($qb->expr()->eq('configkey', $qb->createNamedParameter($key))); - // search within 'indexed' OR 'configvalue' (but if 'flags' is not set as indexed) + // search within 'indexed' OR 'configvalue' only if 'flags' is set as not indexed // TODO: when implementing config lexicon remove the searches on 'configvalue' if value is set as indexed $configValueColumn = ($this->connection->getDatabaseProvider() === IDBConnection::PLATFORM_ORACLE) ? $qb->expr()->castColumn('configvalue', IQueryBuilder::PARAM_STR) : 'configvalue'; if (is_array($value)) { $where = $qb->expr()->orX( $qb->expr()->in('indexed', $qb->createNamedParameter($value, IQueryBuilder::PARAM_STR_ARRAY)), $qb->expr()->andX( - $qb->createFunction('NOT ' . $qb->expr()->bitwiseAnd('flags', self::FLAG_INDEXED)), + $qb->expr()->neq($qb->expr()->bitwiseAnd('flags', self::FLAG_INDEXED), $qb->createNamedParameter(self::FLAG_INDEXED, IQueryBuilder::PARAM_INT)), $qb->expr()->in($configValueColumn, $qb->createNamedParameter($value, IQueryBuilder::PARAM_STR_ARRAY)) ) ); @@ -499,7 +483,7 @@ class UserPreferences implements IUserPreferences { $where = $qb->expr()->orX( $qb->expr()->eq($qb->func()->lower('indexed'), $qb->createNamedParameter(strtolower($value))), $qb->expr()->andX( - $qb->createFunction('NOT ' . $qb->expr()->bitwiseAnd('flags', self::FLAG_INDEXED)), + $qb->expr()->neq($qb->expr()->bitwiseAnd('flags', self::FLAG_INDEXED), $qb->createNamedParameter(self::FLAG_INDEXED, IQueryBuilder::PARAM_INT)), $qb->expr()->eq($qb->func()->lower($configValueColumn), $qb->createNamedParameter(strtolower($value))) ) ); @@ -507,7 +491,7 @@ class UserPreferences implements IUserPreferences { $where = $qb->expr()->orX( $qb->expr()->eq('indexed', $qb->createNamedParameter($value)), $qb->expr()->andX( - $qb->createFunction('NOT ' . $qb->expr()->bitwiseAnd('flags', self::FLAG_INDEXED)), + $qb->expr()->neq($qb->expr()->bitwiseAnd('flags', self::FLAG_INDEXED), $qb->createNamedParameter(self::FLAG_INDEXED, IQueryBuilder::PARAM_INT)), $qb->expr()->eq($configValueColumn, $qb->createNamedParameter($value)) ) ); @@ -515,15 +499,10 @@ class UserPreferences implements IUserPreferences { } $qb->andWhere($where); - - $userIds = []; $result = $qb->executeQuery(); - $rows = $result->fetchAll(); - foreach ($rows as $row) { - $userIds[] = $row['userid']; + while ($row = $result->fetch()) { + yield $row['userid']; } - - return $userIds; } /** @@ -726,7 +705,7 @@ class UserPreferences implements IUserPreferences { bool $lazy, ValueType $type, ): string { - $this->assertParams($userId, $app, $key, valueType: $type); + $this->assertParams($userId, $app, $key); $this->loadPreferences($userId, $lazy); /** @@ -793,7 +772,7 @@ class UserPreferences implements IUserPreferences { * @param string $key preference key * @param bool $lazy lazy loading * - * @return ValueType type of the value + * @return int flags applied to value * @throws UnknownKeyException if preference key is not known * @throws IncorrectTypeException if preferences value type is not known * @since 31.0.0 @@ -978,7 +957,7 @@ class UserPreferences implements IUserPreferences { string $key, bool $value, bool $lazy = false, - int $flags = 0 + int $flags = 0, ): bool { return $this->setTypedValue( $userId, @@ -1058,7 +1037,7 @@ class UserPreferences implements IUserPreferences { int $flags, ValueType $type, ): bool { - $this->assertParams($userId, $app, $key, valueType: $type); + $this->assertParams($userId, $app, $key); $this->loadPreferences($userId, $lazy); $inserted = $refreshCache = false; @@ -1074,7 +1053,7 @@ class UserPreferences implements IUserPreferences { if ($type !== ValueType::ARRAY && $this->isFlagged(self::FLAG_INDEXED, $flags)) { if ($this->isFlagged(self::FLAG_SENSITIVE, $flags)) { $this->logger->warning('sensitive value are not to be indexed'); - } else if (strlen($value) > self::USER_MAX_LENGTH) { + } elseif (strlen($value) > self::USER_MAX_LENGTH) { $this->logger->warning('value is too lengthy to be indexed'); } else { $indexed = $value; @@ -1203,7 +1182,7 @@ class UserPreferences implements IUserPreferences { * @since 31.0.0 */ public function updateType(string $userId, string $app, string $key, ValueType $type = ValueType::MIXED): bool { - $this->assertParams($userId, $app, $key, valueType: $type); + $this->assertParams($userId, $app, $key); $this->loadPreferencesAll($userId); $this->isLazy($userId, $app, $key); // confirm key exists @@ -1348,11 +1327,11 @@ class UserPreferences implements IUserPreferences { $update = $this->connection->getQueryBuilder(); $update->update('preferences') - ->set('flags', $update->createNamedParameter($flags, IQueryBuilder::PARAM_INT)) - ->set('indexed', $update->createNamedParameter($indexed)) - ->where($update->expr()->eq('userid', $update->createNamedParameter($userId))) - ->andWhere($update->expr()->eq('appid', $update->createNamedParameter($app))) - ->andWhere($update->expr()->eq('configkey', $update->createNamedParameter($key))); + ->set('flags', $update->createNamedParameter($flags, IQueryBuilder::PARAM_INT)) + ->set('indexed', $update->createNamedParameter($indexed)) + ->where($update->expr()->eq('userid', $update->createNamedParameter($userId))) + ->andWhere($update->expr()->eq('appid', $update->createNamedParameter($app))) + ->andWhere($update->expr()->eq('configkey', $update->createNamedParameter($key))); $update->executeStatement(); $this->valueDetails[$userId][$app][$key]['flags'] = $flags; @@ -1634,7 +1613,6 @@ class UserPreferences implements IUserPreferences { string $prefKey = '', bool $allowEmptyUser = false, bool $allowEmptyApp = false, - ?ValueType $valueType = null, ): void { if (!$allowEmptyUser && $userId === '') { throw new InvalidArgumentException('userId cannot be an empty string'); @@ -1651,12 +1629,6 @@ class UserPreferences implements IUserPreferences { if (strlen($prefKey) > self::KEY_MAX_LENGTH) { throw new InvalidArgumentException('Value (' . $prefKey . ') for key is too long (' . self::KEY_MAX_LENGTH . ')'); } - if ($valueType !== null) { -// $valueFlag = $valueType->value; -// if (ValueType::tryFrom($valueFlag) === null) { -// throw new InvalidArgumentException('Unknown value type'); -// } - } } private function loadPreferencesAll(string $userId): void { @@ -1697,7 +1669,7 @@ class UserPreferences implements IUserPreferences { } else { $this->fastCache[$userId][$row['appid']][$row['configkey']] = $row['configvalue'] ?? ''; } - $this->valueDetails[$userId][$row['appid']][$row['configkey']] = ['type' => ValueType::from((int)($row['type'] ?? 0)), 'flags' => (int) $row['flags']]; + $this->valueDetails[$userId][$row['appid']][$row['configkey']] = ['type' => ValueType::from((int)($row['type'] ?? 0)), 'flags' => (int)$row['flags']]; } $result->closeCursor(); $this->setAsLoaded($userId, $lazy); diff --git a/lib/private/Server.php b/lib/private/Server.php index 10d6dee9d07..e109636f1fa 100644 --- a/lib/private/Server.php +++ b/lib/private/Server.php @@ -138,6 +138,7 @@ use OCP\Collaboration\AutoComplete\IManager; use OCP\Collaboration\Reference\IReferenceManager; use OCP\Command\IBus; use OCP\Comments\ICommentsManager; +use OCP\Config\IUserPreferences; use OCP\Contacts\ContactsMenu\IActionFactory; use OCP\Contacts\ContactsMenu\IContactsStore; use OCP\Defaults; @@ -237,7 +238,6 @@ use OCP\User\Events\UserLoggedInEvent; use OCP\User\Events\UserLoggedInWithCookieEvent; use OCP\User\Events\UserLoggedOutEvent; use OCP\User\IAvailabilityCoordinator; -use OCP\UserPreferences\IUserPreferences; use Psr\Container\ContainerExceptionInterface; use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; @@ -568,7 +568,7 @@ class Server extends ServerContainer implements IServerContainer { }); $this->registerAlias(IAppConfig::class, \OC\AppConfig::class); - $this->registerAlias(IUserPreferences::class, \OC\UserPreferences::class); + $this->registerAlias(IUserPreferences::class, \OC\Config\UserPreferences::class); $this->registerService(IFactory::class, function (Server $c) { return new \OC\L10N\Factory( diff --git a/lib/public/UserPreferences/Exceptions/UserPreferencesException.php b/lib/public/Config/Exceptions/IncorrectTypeException.php similarity index 68% rename from lib/public/UserPreferences/Exceptions/UserPreferencesException.php rename to lib/public/Config/Exceptions/IncorrectTypeException.php index 664181d420b..dafbbacff78 100644 --- a/lib/public/UserPreferences/Exceptions/UserPreferencesException.php +++ b/lib/public/Config/Exceptions/IncorrectTypeException.php @@ -6,12 +6,12 @@ declare(strict_types=1); * SPDX-License-Identifier: AGPL-3.0-or-later */ -namespace OCP\UserPreferences\Exceptions; +namespace OCP\Config\Exceptions; use Exception; /** * @since 31.0.0 */ -class UserPreferencesException extends Exception { +class IncorrectTypeException extends Exception { } diff --git a/lib/public/UserPreferences/Exceptions/TypeConflictException.php b/lib/public/Config/Exceptions/TypeConflictException.php similarity index 64% rename from lib/public/UserPreferences/Exceptions/TypeConflictException.php rename to lib/public/Config/Exceptions/TypeConflictException.php index b67113fbba7..0b3c903cb38 100644 --- a/lib/public/UserPreferences/Exceptions/TypeConflictException.php +++ b/lib/public/Config/Exceptions/TypeConflictException.php @@ -6,10 +6,12 @@ declare(strict_types=1); * SPDX-License-Identifier: AGPL-3.0-or-later */ -namespace OCP\UserPreferences\Exceptions; +namespace OCP\Config\Exceptions; + +use Exception; /** * @since 31.0.0 */ -class TypeConflictException extends UserPreferencesException { +class TypeConflictException extends Exception { } diff --git a/lib/public/UserPreferences/Exceptions/UnknownKeyException.php b/lib/public/Config/Exceptions/UnknownKeyException.php similarity index 64% rename from lib/public/UserPreferences/Exceptions/UnknownKeyException.php rename to lib/public/Config/Exceptions/UnknownKeyException.php index 3df66689964..2150246f1d2 100644 --- a/lib/public/UserPreferences/Exceptions/UnknownKeyException.php +++ b/lib/public/Config/Exceptions/UnknownKeyException.php @@ -6,10 +6,12 @@ declare(strict_types=1); * SPDX-License-Identifier: AGPL-3.0-or-later */ -namespace OCP\UserPreferences\Exceptions; +namespace OCP\Config\Exceptions; + +use Exception; /** * @since 31.0.0 */ -class UnknownKeyException extends UserPreferencesException { +class UnknownKeyException extends Exception { } diff --git a/lib/public/UserPreferences/IUserPreferences.php b/lib/public/Config/IUserPreferences.php similarity index 95% rename from lib/public/UserPreferences/IUserPreferences.php rename to lib/public/Config/IUserPreferences.php index f2635c0ffaf..18c7fdcd665 100644 --- a/lib/public/UserPreferences/IUserPreferences.php +++ b/lib/public/Config/IUserPreferences.php @@ -6,16 +6,34 @@ declare(strict_types=1); * SPDX-License-Identifier: AGPL-3.0-or-later */ -namespace OCP\UserPreferences; +namespace OCP\Config; -use OCP\UserPreferences\Exceptions\IncorrectTypeException; -use OCP\UserPreferences\Exceptions\UnknownKeyException; +use Generator; +use OCP\Config\Exceptions\IncorrectTypeException; +use OCP\Config\Exceptions\UnknownKeyException; /** + * This class provides an easy way for apps to store user preferences in the + * database. + * Supports **lazy loading** + * + * ### What is lazy loading ? + * In order to avoid loading useless user preferences into memory for each request, + * only non-lazy values are now loaded. + * + * Once a value that is lazy is requested, all lazy values will be loaded. + * + * Similarly, some methods from this class are marked with a warning about ignoring + * lazy loading. Use them wisely and only on parts of the code that are called + * during specific requests or actions to avoid loading the lazy values all the time. + * * @since 31.0.0 */ + interface IUserPreferences { + /** @since 31.0.0 */ public const FLAG_SENSITIVE = 1; // value is sensitive + /** @since 31.0.0 */ public const FLAG_INDEXED = 2; // value should be indexed /** @@ -191,10 +209,10 @@ interface IUserPreferences { * @param string $value preference value * @param bool $caseInsensitive non-case-sensitive search, only works if $value is a string * - * @return list + * @return Generator * @since 31.0.0 */ - public function searchUsersByValueString(string $app, string $key, string $value, bool $caseInsensitive = false): array; + public function searchUsersByValueString(string $app, string $key, string $value, bool $caseInsensitive = false): Generator; /** * List all users storing a specific preference key/value pair. @@ -206,10 +224,10 @@ interface IUserPreferences { * @param string $key preference key * @param int $value preference value * - * @return list + * @return Generator * @since 31.0.0 */ - public function searchUsersByValueInt(string $app, string $key, int $value): array; + public function searchUsersByValueInt(string $app, string $key, int $value): Generator; /** * List all users storing a specific preference key/value pair. @@ -221,10 +239,10 @@ interface IUserPreferences { * @param string $key preference key * @param array $values list of possible preference values * - * @return list + * @return Generator * @since 31.0.0 */ - public function searchUsersByValues(string $app, string $key, array $values): array; + public function searchUsersByValues(string $app, string $key, array $values): Generator; /** * List all users storing a specific preference key/value pair. @@ -236,10 +254,10 @@ interface IUserPreferences { * @param string $key preference key * @param bool $value preference value * - * @return list + * @return Generator * @since 31.0.0 */ - public function searchUsersByValueBool(string $app, string $key, bool $value): array; + public function searchUsersByValueBool(string $app, string $key, bool $value): Generator; /** * Get user preference assigned to a preference key. diff --git a/lib/public/UserPreferences/ValueType.php b/lib/public/Config/ValueType.php similarity index 87% rename from lib/public/UserPreferences/ValueType.php rename to lib/public/Config/ValueType.php index 280dc5a8b42..caf510046c2 100644 --- a/lib/public/UserPreferences/ValueType.php +++ b/lib/public/Config/ValueType.php @@ -6,15 +6,14 @@ declare(strict_types=1); * SPDX-License-Identifier: AGPL-3.0-or-later */ -namespace OCP\UserPreferences; +namespace OCP\Config; -use OCP\UserPreferences\Exceptions\IncorrectTypeException; +use OCP\Config\Exceptions\IncorrectTypeException; use UnhandledMatchError; /** - * Listing of available value type for user preferences + * Listing of available value type for typed config value * - * @see IUserPreferences * @since 31.0.0 */ enum ValueType: int { @@ -50,7 +49,7 @@ enum ValueType: int { 'bool' => self::BOOL, 'array' => self::ARRAY }; - } catch (\UnhandledMatchError ) { + } catch (\UnhandledMatchError) { throw new IncorrectTypeException('unknown string definition'); } } diff --git a/lib/public/IConfig.php b/lib/public/IConfig.php index 3bc64c5e133..f434f838d45 100644 --- a/lib/public/IConfig.php +++ b/lib/public/IConfig.php @@ -245,7 +245,7 @@ interface IConfig { * @param string $appName the app to get the user for * @param string $key the key to get the user for * @param string $value the value to get the user for - * @return list of user IDs + * @return array of user IDs * @since 31.0.0 return type of `list` * @since 8.0.0 */ diff --git a/lib/public/UserPreferences/Exceptions/IncorrectTypeException.php b/lib/public/UserPreferences/Exceptions/IncorrectTypeException.php deleted file mode 100644 index 5c8f83dee5e..00000000000 --- a/lib/public/UserPreferences/Exceptions/IncorrectTypeException.php +++ /dev/null @@ -1,15 +0,0 @@ -connection, $this->logger, $this->crypto, @@ -775,7 +775,7 @@ class UserPreferencesTest extends TestCase { array $result, ): void { $preferences = $this->generateUserPreferences(); - $this->assertEqualsCanonicalizing($result, $preferences->searchUsersByValueString($app, $key, $value, $ci)); + $this->assertEqualsCanonicalizing($result, iterator_to_array($preferences->searchUsersByValueString($app, $key, $value, $ci))); } public function providerSearchValuesByValueInt(): array { @@ -796,7 +796,7 @@ class UserPreferencesTest extends TestCase { array $result, ): void { $preferences = $this->generateUserPreferences(); - $this->assertEqualsCanonicalizing($result, $preferences->searchUsersByValueInt($app, $key, $value)); + $this->assertEqualsCanonicalizing($result, iterator_to_array($preferences->searchUsersByValueInt($app, $key, $value))); } public function providerSearchValuesByValues(): array { @@ -816,7 +816,7 @@ class UserPreferencesTest extends TestCase { array $result, ): void { $preferences = $this->generateUserPreferences(); - $this->assertEqualsCanonicalizing($result, $preferences->searchUsersByValues($app, $key, $values)); + $this->assertEqualsCanonicalizing($result, iterator_to_array($preferences->searchUsersByValues($app, $key, $values))); } public function providerSearchValuesByValueBool(): array { @@ -836,7 +836,7 @@ class UserPreferencesTest extends TestCase { array $result, ): void { $preferences = $this->generateUserPreferences(); - $this->assertEqualsCanonicalizing($result, $preferences->searchUsersByValueBool($app, $key, $value)); + $this->assertEqualsCanonicalizing($result, iterator_to_array($preferences->searchUsersByValueBool($app, $key, $value))); } public function providerGetValueMixed(): array { -- 2.39.5