feat(user-prefs): iterator instead of array on search

Signed-off-by: Maxence Lange <maxence@artificial-owl.com>
This commit is contained in:
Maxence Lange 2024-10-21 18:31:14 -01:00
parent e73513bdd1
commit 7c04818c5c
14 changed files with 114 additions and 139 deletions

View file

@ -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');

View file

@ -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',

View file

@ -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',

View file

@ -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<string> of user IDs
* @return array<string> 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<string> of user IDs
* @return array<string> 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() {

View file

@ -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<string, array<string, array<string, mixed>>> ['user_id' => ['app_id' => ['key' => 'value']]] */
private array $lazyCache = []; // cache for lazy preference keys
/** @var array<string, array<string, array<string, <'type', ValueType>|<'flags', int>> ['user_id' => ['app_id' => ['key' => ['type' => ValueType, 'flags' => bitflag]]] */
/** @var array<string, array<string, array<string, array<string, mixed>>>> ['user_id' => ['app_id' => ['key' => ['type' => ValueType, 'flags' => bitflag]]]] */
private array $valueDetails = []; // type for all preference values
/** @var array<string, array<string, array<string, ValueType>>> ['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<string>
* @return Generator<string>
* @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<string>
* @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<string>
* @return Generator<string>
* @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<string>
* @return Generator<string>
* @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<string>
* @return Generator<string>
* @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<string>
* @return Generator<string>
*/
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);

View file

@ -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(

View file

@ -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 {
}

View file

@ -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 {
}

View file

@ -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 {
}

View file

@ -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<string>
* @return Generator<string>
* @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<string>
* @return Generator<string>
* @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<string>
* @return Generator<string>
* @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<string>
* @return Generator<string>
* @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.

View file

@ -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');
}
}

View file

@ -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<string> of user IDs
* @return array<string> of user IDs
* @since 31.0.0 return type of `list<string>`
* @since 8.0.0
*/

View file

@ -1,15 +0,0 @@
<?php
declare(strict_types=1);
/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OCP\UserPreferences\Exceptions;
/**
* @since 31.0.0
*/
class IncorrectTypeException extends UserPreferencesException {
}

View file

@ -7,13 +7,13 @@ declare(strict_types=1);
*/
namespace lib;
use OC\UserPreferences;
use OC\Config\UserPreferences;
use OCP\Config\Exceptions\TypeConflictException;
use OCP\Config\Exceptions\UnknownKeyException;
use OCP\Config\IUserPreferences;
use OCP\Config\ValueType;
use OCP\IDBConnection;
use OCP\Security\ICrypto;
use OCP\UserPreferences\Exceptions\TypeConflictException;
use OCP\UserPreferences\Exceptions\UnknownKeyException;
use OCP\UserPreferences\IUserPreferences;
use OCP\UserPreferences\ValueType;
use Psr\Log\LoggerInterface;
use Test\TestCase;
@ -275,7 +275,7 @@ class UserPreferencesTest extends TestCase {
* @return IUserPreferences
*/
private function generateUserPreferences(array $preLoading = []): IUserPreferences {
$preferences = new \OC\UserPreferences(
$preferences = new \OC\Config\UserPreferences(
$this->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 {