From 7ac46b746b5ba85e253b730b0e46efd62470f997 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=B4me=20Chilliet?= Date: Thu, 12 Mar 2026 16:32:21 +0100 Subject: [PATCH 01/17] fix: Remove static var in NaturalSort MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Côme Chilliet --- lib/private/NaturalSort.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/private/NaturalSort.php b/lib/private/NaturalSort.php index 240d4de637a1e..d367cc9d6e960 100644 --- a/lib/private/NaturalSort.php +++ b/lib/private/NaturalSort.php @@ -11,7 +11,6 @@ use Psr\Log\LoggerInterface; class NaturalSort { - private static $instance; private $collator; private $cache = []; @@ -113,10 +112,7 @@ public function compare($a, $b) { * Returns a singleton * @return NaturalSort instance */ - public static function getInstance() { - if (!isset(self::$instance)) { - self::$instance = new NaturalSort(); - } - return self::$instance; + public static function getInstance(): NaturalSort { + return \OCP\Server::get(NaturalSort::class); } } From 73ebabf6fc2b16f9aa86abd7efc54af1a2a82b4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=B4me=20Chilliet?= Date: Fri, 13 Mar 2026 10:44:31 +0100 Subject: [PATCH 02/17] fix: Remove useless static property in OCP\Util MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Côme Chilliet --- lib/public/Util.php | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/lib/public/Util.php b/lib/public/Util.php index 0610460fc2237..0ecfc95075b4f 100644 --- a/lib/public/Util.php +++ b/lib/public/Util.php @@ -412,24 +412,13 @@ public static function emitHook($signalclass, $signalname, $params = []) { return \OC_Hook::emit($signalclass, $signalname, $params); } - /** - * Cached encrypted CSRF token. Some static unit-tests of ownCloud compare - * multiple Template elements which invoke `callRegister`. If the value - * would not be cached these unit-tests would fail. - * @var string - */ - private static $token = ''; - /** * Register an get/post call. This is important to prevent CSRF attacks * @since 4.5.0 * @deprecated 32.0.0 directly use CsrfTokenManager instead */ public static function callRegister() { - if (self::$token === '') { - self::$token = \OCP\Server::get(CsrfTokenManager::class)->getToken()->getEncryptedValue(); - } - return self::$token; + return \OCP\Server::get(CsrfTokenManager::class)->getToken()->getEncryptedValue(); } /** From 057752c84c09e07a842e052610743d2ef3e74e1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=B4me=20Chilliet?= Date: Fri, 13 Mar 2026 11:57:21 +0100 Subject: [PATCH 03/17] fix: Remove static var in AppManager MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Côme Chilliet --- lib/private/App/AppManager.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/private/App/AppManager.php b/lib/private/App/AppManager.php index 6eddb2b2c41e6..9bf5909cce99b 100644 --- a/lib/private/App/AppManager.php +++ b/lib/private/App/AppManager.php @@ -54,6 +54,9 @@ class AppManager implements IAppManager { /** @var string[] $appId => $enabled */ private array $enabledAppsCache = []; + /** @var array $appId => approot information */ + private array $appsDirCache = []; + /** @var string[]|null */ private ?array $shippedApps = null; @@ -743,11 +746,9 @@ public function findAppInDirectories(string $appId, bool $ignoreCache = false) { if ($sanitizedAppId !== $appId) { return false; } - // FIXME replace by a property or a cache - static $app_dir = []; - if (isset($app_dir[$appId]) && !$ignoreCache) { - return $app_dir[$appId]; + if (isset($this->appsDirCache[$appId]) && !$ignoreCache) { + return $this->appsDirCache[$appId]; } $possibleApps = []; @@ -761,7 +762,7 @@ public function findAppInDirectories(string $appId, bool $ignoreCache = false) { return false; } elseif (count($possibleApps) === 1) { $dir = array_shift($possibleApps); - $app_dir[$appId] = $dir; + $this->appsDirCache[$appId] = $dir; return $dir; } else { $versionToLoad = []; @@ -778,7 +779,7 @@ public function findAppInDirectories(string $appId, bool $ignoreCache = false) { if (!isset($versionToLoad['dir'])) { return false; } - $app_dir[$appId] = $versionToLoad['dir']; + $this->appsDirCache[$appId] = $versionToLoad['dir']; return $versionToLoad['dir']; } } From 04d2c6a8d5afd6b0672c3d8fab6a8e92edf66271 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=B4me=20Chilliet?= Date: Fri, 13 Mar 2026 11:58:29 +0100 Subject: [PATCH 04/17] fix: Remove static var in Memcache/Redis MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Côme Chilliet --- lib/private/Memcache/Redis.php | 15 +++++---------- lib/private/RedisFactory.php | 13 ++++++------- lib/private/Server.php | 5 +---- 3 files changed, 12 insertions(+), 21 deletions(-) diff --git a/lib/private/Memcache/Redis.php b/lib/private/Memcache/Redis.php index 1611d428f3016..bc0a2a47d3aa2 100644 --- a/lib/private/Memcache/Redis.php +++ b/lib/private/Memcache/Redis.php @@ -7,6 +7,7 @@ */ namespace OC\Memcache; +use OC\RedisFactory; use OCP\IMemcacheTTL; use OCP\Server; @@ -37,24 +38,18 @@ class Redis extends Cache implements IMemcacheTTL { private const MAX_TTL = 30 * 24 * 60 * 60; // 1 month - /** - * @var \Redis|\RedisCluster $cache - */ - private static $cache = null; + private \Redis|\RedisCluster $cache; public function __construct($prefix = '', string $logFile = '') { parent::__construct($prefix); + $this->cache = \OCP\Server::get(RedisFactory::class)->getInstance(); } /** - * @return \Redis|\RedisCluster|null * @throws \Exception */ - public function getCache() { - if (is_null(self::$cache)) { - self::$cache = Server::get('RedisFactory')->getInstance(); - } - return self::$cache; + public function getCache(): \Redis|\RedisCluster { + return $this->cache; } public function get($key) { diff --git a/lib/private/RedisFactory.php b/lib/private/RedisFactory.php index 4c8160d81d1f1..fb90e59a5725c 100644 --- a/lib/private/RedisFactory.php +++ b/lib/private/RedisFactory.php @@ -131,15 +131,14 @@ private function getSslContext(array $config): ?array { } public function getInstance(): \Redis|\RedisCluster { - if (!$this->isAvailable()) { - throw new \Exception('Redis support is not available'); - } if ($this->instance === null) { + if (!$this->isAvailable()) { + throw new \Exception('Redis support is not available'); + } $this->create(); - } - - if ($this->instance === null) { - throw new \Exception('Redis support is not available'); + if ($this->instance === null) { + throw new \Exception('Redis support is not available'); + } } return $this->instance; diff --git a/lib/private/Server.php b/lib/private/Server.php index 05af431c00f12..28ce2589f637c 100644 --- a/lib/private/Server.php +++ b/lib/private/Server.php @@ -671,10 +671,7 @@ public function __construct( }); $this->registerAlias(ICacheFactory::class, Factory::class); - $this->registerService('RedisFactory', function (Server $c) { - $systemConfig = $c->get(SystemConfig::class); - return new RedisFactory($systemConfig, $c->get(IEventLogger::class)); - }); + $this->registerDeprecatedAlias('RedisFactory', RedisFactory::class); $this->registerService(\OCP\Activity\IManager::class, function (Server $c) { $l10n = $this->get(IFactory::class)->get('lib'); From a710680786e27ed0df13c5ee106babcdbd32aac5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=B4me=20Chilliet?= Date: Fri, 13 Mar 2026 12:00:16 +0100 Subject: [PATCH 05/17] fix: Remove static vars in TaskProcessing, TextProcessing, TextToImage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Côme Chilliet --- lib/private/TaskProcessing/Db/Task.php | 8 ++++---- lib/private/TaskProcessing/Db/TaskMapper.php | 16 ++++++++-------- lib/private/TextProcessing/Db/Task.php | 9 ++++----- lib/private/TextProcessing/Db/TaskMapper.php | 6 +++--- lib/private/TextProcessing/Manager.php | 17 ++++++++++------- lib/private/TextToImage/Db/Task.php | 8 ++++---- lib/private/TextToImage/Db/TaskMapper.php | 6 +++--- 7 files changed, 36 insertions(+), 34 deletions(-) diff --git a/lib/private/TaskProcessing/Db/Task.php b/lib/private/TaskProcessing/Db/Task.php index 3ac4facf97eab..7b30de57d5284 100644 --- a/lib/private/TaskProcessing/Db/Task.php +++ b/lib/private/TaskProcessing/Db/Task.php @@ -76,12 +76,12 @@ class Task extends Entity { /** * @var string[] */ - public static array $columns = ['id', 'last_updated', 'type', 'input', 'output', 'status', 'user_id', 'app_id', 'custom_id', 'completion_expected_at', 'error_message', 'progress', 'webhook_uri', 'webhook_method', 'scheduled_at', 'started_at', 'ended_at', 'allow_cleanup', 'user_facing_error_message', 'include_watermark']; + public const array COLUMNS = ['id', 'last_updated', 'type', 'input', 'output', 'status', 'user_id', 'app_id', 'custom_id', 'completion_expected_at', 'error_message', 'progress', 'webhook_uri', 'webhook_method', 'scheduled_at', 'started_at', 'ended_at', 'allow_cleanup', 'user_facing_error_message', 'include_watermark']; /** * @var string[] */ - public static array $fields = ['id', 'lastUpdated', 'type', 'input', 'output', 'status', 'userId', 'appId', 'customId', 'completionExpectedAt', 'errorMessage', 'progress', 'webhookUri', 'webhookMethod', 'scheduledAt', 'startedAt', 'endedAt', 'allowCleanup', 'userFacingErrorMessage', 'includeWatermark']; + public const array FIELDS = ['id', 'lastUpdated', 'type', 'input', 'output', 'status', 'userId', 'appId', 'customId', 'completionExpectedAt', 'errorMessage', 'progress', 'webhookUri', 'webhookMethod', 'scheduledAt', 'startedAt', 'endedAt', 'allowCleanup', 'userFacingErrorMessage', 'includeWatermark']; public function __construct() { @@ -109,9 +109,9 @@ public function __construct() { } public function toRow(): array { - return array_combine(self::$columns, array_map(function ($field) { + return array_combine(self::COLUMNS, array_map(function ($field) { return $this->{'get' . ucfirst($field)}(); - }, self::$fields)); + }, self::FIELDS)); } public static function fromPublicTask(OCPTask $task): self { diff --git a/lib/private/TaskProcessing/Db/TaskMapper.php b/lib/private/TaskProcessing/Db/TaskMapper.php index f62bb41be3b77..08afdfd923e0a 100644 --- a/lib/private/TaskProcessing/Db/TaskMapper.php +++ b/lib/private/TaskProcessing/Db/TaskMapper.php @@ -38,7 +38,7 @@ public function __construct( */ public function find(int $id): Task { $qb = $this->db->getQueryBuilder(); - $qb->select(Task::$columns) + $qb->select(Task::COLUMNS) ->from($this->tableName) ->where($qb->expr()->eq('id', $qb->createPositionalParameter($id))); return $this->findEntity($qb); @@ -53,7 +53,7 @@ public function find(int $id): Task { */ public function findOldestScheduledByType(array $taskTypes, array $taskIdsToIgnore): Task { $qb = $this->db->getQueryBuilder(); - $qb->select(Task::$columns) + $qb->select(Task::COLUMNS) ->from($this->tableName) ->where($qb->expr()->eq('status', $qb->createPositionalParameter(\OCP\TaskProcessing\Task::STATUS_SCHEDULED, IQueryBuilder::PARAM_INT))) ->setMaxResults(1) @@ -85,7 +85,7 @@ public function findOldestScheduledByType(array $taskTypes, array $taskIdsToIgno */ public function findByIdAndUser(int $id, ?string $userId): Task { $qb = $this->db->getQueryBuilder(); - $qb->select(Task::$columns) + $qb->select(Task::COLUMNS) ->from($this->tableName) ->where($qb->expr()->eq('id', $qb->createPositionalParameter($id))); if ($userId === null) { @@ -105,7 +105,7 @@ public function findByIdAndUser(int $id, ?string $userId): Task { */ public function findByUserAndTaskType(?string $userId, ?string $taskType = null, ?string $customId = null): array { $qb = $this->db->getQueryBuilder(); - $qb->select(Task::$columns) + $qb->select(Task::COLUMNS) ->from($this->tableName) ->where($qb->expr()->eq('user_id', $qb->createPositionalParameter($userId))); if ($taskType !== null) { @@ -126,7 +126,7 @@ public function findByUserAndTaskType(?string $userId, ?string $taskType = null, */ public function findUserTasksByApp(?string $userId, string $appId, ?string $customId = null): array { $qb = $this->db->getQueryBuilder(); - $qb->select(Task::$columns) + $qb->select(Task::COLUMNS) ->from($this->tableName) ->where($qb->expr()->eq('user_id', $qb->createPositionalParameter($userId))) ->andWhere($qb->expr()->eq('app_id', $qb->createPositionalParameter($appId))); @@ -151,7 +151,7 @@ public function findTasks( ?string $userId, ?string $taskType = null, ?string $appId = null, ?string $customId = null, ?int $status = null, ?int $scheduleAfter = null, ?int $endedBefore = null): array { $qb = $this->db->getQueryBuilder(); - $qb->select(Task::$columns) + $qb->select(Task::COLUMNS) ->from($this->tableName); // empty string: no userId filter @@ -205,7 +205,7 @@ public function deleteOlderThan(int $timeout, bool $force = false): int { */ public function getTasksToCleanup(int $timeout, bool $force = false): \Generator { $qb = $this->db->getQueryBuilder(); - $qb->select(Task::$columns) + $qb->select(Task::COLUMNS) ->from($this->tableName) ->where($qb->expr()->lt('last_updated', $qb->createPositionalParameter($this->timeFactory->getDateTime()->getTimestamp() - $timeout))); if (!$force) { @@ -243,7 +243,7 @@ public function lockTask(Entity $entity): int { */ public function findNOldestScheduledByType(array $taskTypes, array $taskIdsToIgnore, int $numberOfTasks) { $qb = $this->db->getQueryBuilder(); - $qb->select(Task::$columns) + $qb->select(Task::COLUMNS) ->from($this->tableName) ->where($qb->expr()->eq('status', $qb->createPositionalParameter(\OCP\TaskProcessing\Task::STATUS_SCHEDULED, IQueryBuilder::PARAM_INT))) ->setMaxResults($numberOfTasks) diff --git a/lib/private/TextProcessing/Db/Task.php b/lib/private/TextProcessing/Db/Task.php index d4ebc19e74a7e..1bb018415ee9c 100644 --- a/lib/private/TextProcessing/Db/Task.php +++ b/lib/private/TextProcessing/Db/Task.php @@ -46,13 +46,12 @@ class Task extends Entity { /** * @var string[] */ - public static array $columns = ['id', 'last_updated', 'type', 'input', 'output', 'status', 'user_id', 'app_id', 'identifier', 'completion_expected_at']; + public const array COLUMNS = ['id', 'last_updated', 'type', 'input', 'output', 'status', 'user_id', 'app_id', 'identifier', 'completion_expected_at']; /** * @var string[] */ - public static array $fields = ['id', 'lastUpdated', 'type', 'input', 'output', 'status', 'userId', 'appId', 'identifier', 'completionExpectedAt']; - + public const array FIELDS = ['id', 'lastUpdated', 'type', 'input', 'output', 'status', 'userId', 'appId', 'identifier', 'completionExpectedAt']; public function __construct() { // add types in constructor @@ -69,9 +68,9 @@ public function __construct() { } public function toRow(): array { - return array_combine(self::$columns, array_map(function ($field) { + return array_combine(self::COLUMNS, array_map(function ($field) { return $this->{'get' . ucfirst($field)}(); - }, self::$fields)); + }, self::FIELDS)); } public static function fromPublicTask(OCPTask $task): Task { diff --git a/lib/private/TextProcessing/Db/TaskMapper.php b/lib/private/TextProcessing/Db/TaskMapper.php index b03e5833958bf..2833a25378d52 100644 --- a/lib/private/TextProcessing/Db/TaskMapper.php +++ b/lib/private/TextProcessing/Db/TaskMapper.php @@ -37,7 +37,7 @@ public function __construct( */ public function find(int $id): Task { $qb = $this->db->getQueryBuilder(); - $qb->select(Task::$columns) + $qb->select(Task::COLUMNS) ->from($this->tableName) ->where($qb->expr()->eq('id', $qb->createPositionalParameter($id))); return $this->findEntity($qb); @@ -53,7 +53,7 @@ public function find(int $id): Task { */ public function findByIdAndUser(int $id, ?string $userId): Task { $qb = $this->db->getQueryBuilder(); - $qb->select(Task::$columns) + $qb->select(Task::COLUMNS) ->from($this->tableName) ->where($qb->expr()->eq('id', $qb->createPositionalParameter($id))); if ($userId === null) { @@ -73,7 +73,7 @@ public function findByIdAndUser(int $id, ?string $userId): Task { */ public function findUserTasksByApp(string $userId, string $appId, ?string $identifier = null): array { $qb = $this->db->getQueryBuilder(); - $qb->select(Task::$columns) + $qb->select(Task::COLUMNS) ->from($this->tableName) ->where($qb->expr()->eq('user_id', $qb->createPositionalParameter($userId))) ->andWhere($qb->expr()->eq('app_id', $qb->createPositionalParameter($appId))); diff --git a/lib/private/TextProcessing/Manager.php b/lib/private/TextProcessing/Manager.php index 3fe45ce55ece2..b6021246c0199 100644 --- a/lib/private/TextProcessing/Manager.php +++ b/lib/private/TextProcessing/Manager.php @@ -44,7 +44,10 @@ class Manager implements IManager { /** @var ?IProvider[] */ private ?array $providers = null; - private static array $taskProcessingCompatibleTaskTypes = [ + /** + * @var array + */ + private const array COMPATIBLE_TASK_TYPES = [ FreePromptTaskType::class => TextToText::ID, HeadlineTaskType::class => TextToTextHeadline::ID, SummaryTaskType::class => TextToTextSummary::ID, @@ -91,7 +94,7 @@ public function getProviders(): array { public function hasProviders(): bool { // check if task processing equivalent types are available $taskTaskTypes = $this->taskProcessingManager->getAvailableTaskTypes(); - foreach (self::$taskProcessingCompatibleTaskTypes as $textTaskTypeClass => $taskTaskTypeId) { + foreach (self::COMPATIBLE_TASK_TYPES as $textTaskTypeClass => $taskTaskTypeId) { if (isset($taskTaskTypes[$taskTaskTypeId])) { return true; } @@ -115,7 +118,7 @@ public function getAvailableTaskTypes(): array { // check if task processing equivalent types are available $taskTaskTypes = $this->taskProcessingManager->getAvailableTaskTypes(); - foreach (self::$taskProcessingCompatibleTaskTypes as $textTaskTypeClass => $taskTaskTypeId) { + foreach (self::COMPATIBLE_TASK_TYPES as $textTaskTypeClass => $taskTaskTypeId) { if (isset($taskTaskTypes[$taskTaskTypeId])) { $tasks[$textTaskTypeClass] = true; } @@ -134,9 +137,9 @@ public function canHandleTask(OCPTask $task): bool { public function runTask(OCPTask $task): string { // try to run a task processing task if possible $taskTypeClass = $task->getType(); - if (isset(self::$taskProcessingCompatibleTaskTypes[$taskTypeClass]) && isset($this->taskProcessingManager->getAvailableTaskTypes()[self::$taskProcessingCompatibleTaskTypes[$taskTypeClass]])) { + if (isset(self::COMPATIBLE_TASK_TYPES[$taskTypeClass]) && isset($this->taskProcessingManager->getAvailableTaskTypes()[self::COMPATIBLE_TASK_TYPES[$taskTypeClass]])) { try { - $taskProcessingTaskTypeId = self::$taskProcessingCompatibleTaskTypes[$taskTypeClass]; + $taskProcessingTaskTypeId = self::COMPATIBLE_TASK_TYPES[$taskTypeClass]; $taskProcessingTask = new \OCP\TaskProcessing\Task( $taskProcessingTaskTypeId, ['input' => $task->getInput()], @@ -222,8 +225,8 @@ public function scheduleTask(OCPTask $task): void { $task->setStatus(OCPTask::STATUS_SCHEDULED); $providers = $this->getPreferredProviders($task); $equivalentTaskProcessingTypeAvailable = ( - isset(self::$taskProcessingCompatibleTaskTypes[$task->getType()]) - && isset($this->taskProcessingManager->getAvailableTaskTypes()[self::$taskProcessingCompatibleTaskTypes[$task->getType()]]) + isset(self::COMPATIBLE_TASK_TYPES[$task->getType()]) + && isset($this->taskProcessingManager->getAvailableTaskTypes()[self::COMPATIBLE_TASK_TYPES[$task->getType()]]) ); if (count($providers) === 0 && !$equivalentTaskProcessingTypeAvailable) { throw new PreConditionNotMetException('No LanguageModel provider is installed that can handle this task'); diff --git a/lib/private/TextToImage/Db/Task.php b/lib/private/TextToImage/Db/Task.php index 48a8bcc6c407d..a3103a8e103fa 100644 --- a/lib/private/TextToImage/Db/Task.php +++ b/lib/private/TextToImage/Db/Task.php @@ -49,12 +49,12 @@ class Task extends Entity { /** * @var string[] */ - public static array $columns = ['id', 'last_updated', 'input', 'status', 'user_id', 'app_id', 'identifier', 'number_of_images', 'completion_expected_at']; + public const array COLUMNS = ['id', 'last_updated', 'input', 'status', 'user_id', 'app_id', 'identifier', 'number_of_images', 'completion_expected_at']; /** * @var string[] */ - public static array $fields = ['id', 'lastUpdated', 'input', 'status', 'userId', 'appId', 'identifier', 'numberOfImages', 'completionExpectedAt']; + public const array FIELDS = ['id', 'lastUpdated', 'input', 'status', 'userId', 'appId', 'identifier', 'numberOfImages', 'completionExpectedAt']; public function __construct() { @@ -71,9 +71,9 @@ public function __construct() { } public function toRow(): array { - return array_combine(self::$columns, array_map(function ($field) { + return array_combine(self::COLUMNS, array_map(function ($field) { return $this->{'get' . ucfirst($field)}(); - }, self::$fields)); + }, self::FIELDS)); } public static function fromPublicTask(OCPTask $task): Task { diff --git a/lib/private/TextToImage/Db/TaskMapper.php b/lib/private/TextToImage/Db/TaskMapper.php index 37f492e14cf3b..31af53c326798 100644 --- a/lib/private/TextToImage/Db/TaskMapper.php +++ b/lib/private/TextToImage/Db/TaskMapper.php @@ -38,7 +38,7 @@ public function __construct( */ public function find(int $id): Task { $qb = $this->db->getQueryBuilder(); - $qb->select(Task::$columns) + $qb->select(Task::COLUMNS) ->from($this->tableName) ->where($qb->expr()->eq('id', $qb->createPositionalParameter($id))); return $this->findEntity($qb); @@ -54,7 +54,7 @@ public function find(int $id): Task { */ public function findByIdAndUser(int $id, ?string $userId): Task { $qb = $this->db->getQueryBuilder(); - $qb->select(Task::$columns) + $qb->select(Task::COLUMNS) ->from($this->tableName) ->where($qb->expr()->eq('id', $qb->createPositionalParameter($id))); if ($userId === null) { @@ -74,7 +74,7 @@ public function findByIdAndUser(int $id, ?string $userId): Task { */ public function findUserTasksByApp(?string $userId, string $appId, ?string $identifier = null): array { $qb = $this->db->getQueryBuilder(); - $qb->select(Task::$columns) + $qb->select(Task::COLUMNS) ->from($this->tableName) ->where($qb->expr()->eq('user_id', $qb->createPositionalParameter($userId))) ->andWhere($qb->expr()->eq('app_id', $qb->createPositionalParameter($appId))); From 477084aea90cc969871087f684e535076e8b4199 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=B4me=20Chilliet?= Date: Tue, 17 Mar 2026 15:12:02 +0100 Subject: [PATCH 06/17] chore: Remove types from const properties MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Support was added in PHP 8.3 and we need to support 8.2 Signed-off-by: Côme Chilliet --- lib/private/TaskProcessing/Db/Task.php | 4 ++-- lib/private/TextProcessing/Db/Task.php | 4 ++-- lib/private/TextToImage/Db/Task.php | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/private/TaskProcessing/Db/Task.php b/lib/private/TaskProcessing/Db/Task.php index 7b30de57d5284..502a67ec3f403 100644 --- a/lib/private/TaskProcessing/Db/Task.php +++ b/lib/private/TaskProcessing/Db/Task.php @@ -76,12 +76,12 @@ class Task extends Entity { /** * @var string[] */ - public const array COLUMNS = ['id', 'last_updated', 'type', 'input', 'output', 'status', 'user_id', 'app_id', 'custom_id', 'completion_expected_at', 'error_message', 'progress', 'webhook_uri', 'webhook_method', 'scheduled_at', 'started_at', 'ended_at', 'allow_cleanup', 'user_facing_error_message', 'include_watermark']; + public const COLUMNS = ['id', 'last_updated', 'type', 'input', 'output', 'status', 'user_id', 'app_id', 'custom_id', 'completion_expected_at', 'error_message', 'progress', 'webhook_uri', 'webhook_method', 'scheduled_at', 'started_at', 'ended_at', 'allow_cleanup', 'user_facing_error_message', 'include_watermark']; /** * @var string[] */ - public const array FIELDS = ['id', 'lastUpdated', 'type', 'input', 'output', 'status', 'userId', 'appId', 'customId', 'completionExpectedAt', 'errorMessage', 'progress', 'webhookUri', 'webhookMethod', 'scheduledAt', 'startedAt', 'endedAt', 'allowCleanup', 'userFacingErrorMessage', 'includeWatermark']; + public const FIELDS = ['id', 'lastUpdated', 'type', 'input', 'output', 'status', 'userId', 'appId', 'customId', 'completionExpectedAt', 'errorMessage', 'progress', 'webhookUri', 'webhookMethod', 'scheduledAt', 'startedAt', 'endedAt', 'allowCleanup', 'userFacingErrorMessage', 'includeWatermark']; public function __construct() { diff --git a/lib/private/TextProcessing/Db/Task.php b/lib/private/TextProcessing/Db/Task.php index 1bb018415ee9c..d6144a69074d3 100644 --- a/lib/private/TextProcessing/Db/Task.php +++ b/lib/private/TextProcessing/Db/Task.php @@ -46,12 +46,12 @@ class Task extends Entity { /** * @var string[] */ - public const array COLUMNS = ['id', 'last_updated', 'type', 'input', 'output', 'status', 'user_id', 'app_id', 'identifier', 'completion_expected_at']; + public const COLUMNS = ['id', 'last_updated', 'type', 'input', 'output', 'status', 'user_id', 'app_id', 'identifier', 'completion_expected_at']; /** * @var string[] */ - public const array FIELDS = ['id', 'lastUpdated', 'type', 'input', 'output', 'status', 'userId', 'appId', 'identifier', 'completionExpectedAt']; + public const FIELDS = ['id', 'lastUpdated', 'type', 'input', 'output', 'status', 'userId', 'appId', 'identifier', 'completionExpectedAt']; public function __construct() { // add types in constructor diff --git a/lib/private/TextToImage/Db/Task.php b/lib/private/TextToImage/Db/Task.php index a3103a8e103fa..79705cb41b208 100644 --- a/lib/private/TextToImage/Db/Task.php +++ b/lib/private/TextToImage/Db/Task.php @@ -49,12 +49,12 @@ class Task extends Entity { /** * @var string[] */ - public const array COLUMNS = ['id', 'last_updated', 'input', 'status', 'user_id', 'app_id', 'identifier', 'number_of_images', 'completion_expected_at']; + public const COLUMNS = ['id', 'last_updated', 'input', 'status', 'user_id', 'app_id', 'identifier', 'number_of_images', 'completion_expected_at']; /** * @var string[] */ - public const array FIELDS = ['id', 'lastUpdated', 'input', 'status', 'userId', 'appId', 'identifier', 'numberOfImages', 'completionExpectedAt']; + public const FIELDS = ['id', 'lastUpdated', 'input', 'status', 'userId', 'appId', 'identifier', 'numberOfImages', 'completionExpectedAt']; public function __construct() { From 54c048c7950e593414c0ae2402d371a8c1caabf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=B4me=20Chilliet?= Date: Fri, 13 Mar 2026 13:09:44 +0100 Subject: [PATCH 07/17] fix: Remove static vars from user_ldap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Côme Chilliet --- apps/user_ldap/lib/Configuration.php | 3 +-- apps/user_ldap/lib/Wizard.php | 29 +++++++++++++--------------- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/apps/user_ldap/lib/Configuration.php b/apps/user_ldap/lib/Configuration.php index b4a5b84720421..42eaa464d5f7a 100644 --- a/apps/user_ldap/lib/Configuration.php +++ b/apps/user_ldap/lib/Configuration.php @@ -571,7 +571,7 @@ public function getDefaults(): array { */ public function getConfigTranslationArray(): array { //TODO: merge them into one representation - static $array = [ + return [ 'ldap_host' => 'ldapHost', 'ldap_port' => 'ldapPort', 'ldap_backup_host' => 'ldapBackupHost', @@ -644,7 +644,6 @@ public function getConfigTranslationArray(): array { 'ldap_attr_anniversarydate' => 'ldapAttributeAnniversaryDate', 'ldap_attr_pronouns' => 'ldapAttributePronouns', ]; - return $array; } /** diff --git a/apps/user_ldap/lib/Wizard.php b/apps/user_ldap/lib/Wizard.php index fa77fea8fa2bb..876f001fb2728 100644 --- a/apps/user_ldap/lib/Wizard.php +++ b/apps/user_ldap/lib/Wizard.php @@ -16,7 +16,7 @@ use Psr\Log\LoggerInterface; class Wizard extends LDAPUtility { - protected static ?IL10N $l = null; + private IL10N $l; protected ?\LDAP\Connection $cr = null; protected WizardResult $result; protected LoggerInterface $logger; @@ -40,9 +40,7 @@ public function __construct( protected Access $access, ) { parent::__construct($ldap); - if (is_null(static::$l)) { - static::$l = Server::get(IL10NFactory::class)->get('user_ldap'); - } + $this->l = Server::get(IL10NFactory::class)->get('user_ldap'); $this->result = new WizardResult(); $this->logger = Server::get(LoggerInterface::class); } @@ -94,7 +92,7 @@ public function countGroups() { $filter = $this->configuration->ldapGroupFilter; if (empty($filter)) { - $output = self::$l->n('%n group found', '%n groups found', 0); + $output = $this->l->n('%n group found', '%n groups found', 0); $this->result->addChange('ldap_group_count', $output); return $this->result; } @@ -110,9 +108,9 @@ public function countGroups() { } if ($groupsTotal > 1000) { - $output = self::$l->t('> 1000 groups found'); + $output = $this->l->t('> 1000 groups found'); } else { - $output = self::$l->n( + $output = $this->l->n( '%n group found', '%n groups found', $groupsTotal @@ -130,9 +128,9 @@ public function countUsers(): WizardResult { $usersTotal = $this->countEntries($filter, 'users'); if ($usersTotal > 1000) { - $output = self::$l->t('> 1000 users found'); + $output = $this->l->t('> 1000 users found'); } else { - $output = self::$l->n( + $output = $this->l->n( '%n user found', '%n users found', $usersTotal @@ -216,7 +214,7 @@ public function detectUserDisplayNameAttribute() { } } - throw new \Exception(self::$l->t('Could not detect user display name attribute. Please specify it yourself in advanced LDAP settings.')); + throw new \Exception($this->l->t('Could not detect user display name attribute. Please specify it yourself in advanced LDAP settings.')); } /** @@ -431,7 +429,7 @@ public function fetchGroups(string $dbKey, string $confKey): array { natsort($groupNames); $this->result->addOptions($dbKey, array_values($groupNames)); } else { - throw new \Exception(self::$l->t('Could not find the desired feature')); + throw new \Exception($this->l->t('Could not find the desired feature')); } $setFeatures = $this->configuration->$confKey; @@ -1024,7 +1022,7 @@ private function connectAndBind(int $port, bool $tls): bool { $host = $this->configuration->ldapHost; $hostInfo = parse_url((string)$host); if (!is_string($host) || !$hostInfo) { - throw new \Exception(self::$l->t('Invalid Host')); + throw new \Exception($this->l->t('Invalid Host')); } $this->logger->debug( 'Wiz: Attempting to connect', @@ -1032,7 +1030,7 @@ private function connectAndBind(int $port, bool $tls): bool { ); $cr = $this->ldap->connect($host, (string)$port); if (!$this->ldap->isResource($cr)) { - throw new \Exception(self::$l->t('Invalid Host')); + throw new \Exception($this->l->t('Invalid Host')); } /** @var \LDAP\Connection $cr */ @@ -1219,7 +1217,7 @@ private function determineFeature(array $objectclasses, string $attr, string $db //sorting in the web UI. Therefore: array_values $this->result->addOptions($dbkey, array_values($availableFeatures)); } else { - throw new \Exception(self::$l->t('Could not find the desired feature')); + throw new \Exception($this->l->t('Could not find the desired feature')); } $setFeatures = $this->configuration->$confkey; @@ -1307,7 +1305,7 @@ private function getConnection(): \LDAP\Connection|false { * @return array */ private function getDefaultLdapPortSettings(): array { - static $settings = [ + return [ ['port' => 7636, 'tls' => false], ['port' => 636, 'tls' => false], ['port' => 7389, 'tls' => true], @@ -1315,7 +1313,6 @@ private function getDefaultLdapPortSettings(): array { ['port' => 7389, 'tls' => false], ['port' => 389, 'tls' => false], ]; - return $settings; } /** From 6f78e7a133af8332e5c24508c6351a4020c6f68b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=B4me=20Chilliet?= Date: Fri, 13 Mar 2026 13:10:25 +0100 Subject: [PATCH 08/17] fix: Remove static vars from applications MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Côme Chilliet --- .../lib/Service/BackupCodeStorage.php | 4 ++-- apps/workflowengine/lib/Command/Index.php | 7 ++++--- apps/workflowengine/lib/Manager.php | 15 ++++++++------- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/apps/twofactor_backupcodes/lib/Service/BackupCodeStorage.php b/apps/twofactor_backupcodes/lib/Service/BackupCodeStorage.php index 7dd6b3949e2d2..24621ba2ee202 100644 --- a/apps/twofactor_backupcodes/lib/Service/BackupCodeStorage.php +++ b/apps/twofactor_backupcodes/lib/Service/BackupCodeStorage.php @@ -17,7 +17,7 @@ use OCP\Security\ISecureRandom; class BackupCodeStorage { - private static $CODE_LENGTH = 16; + private const CODE_LENGTH = 16; public function __construct( private BackupCodeMapper $mapper, @@ -40,7 +40,7 @@ public function createCodes(IUser $user, int $number = 10): array { $uid = $user->getUID(); foreach (range(1, min([$number, 20])) as $i) { - $code = $this->random->generate(self::$CODE_LENGTH, ISecureRandom::CHAR_HUMAN_READABLE); + $code = $this->random->generate(self::CODE_LENGTH, ISecureRandom::CHAR_HUMAN_READABLE); $dbCode = new BackupCode(); $dbCode->setUserId($uid); diff --git a/apps/workflowengine/lib/Command/Index.php b/apps/workflowengine/lib/Command/Index.php index 1fb8cb416b0aa..c38d19a087ede 100644 --- a/apps/workflowengine/lib/Command/Index.php +++ b/apps/workflowengine/lib/Command/Index.php @@ -6,6 +6,7 @@ * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later */ + namespace OCA\WorkflowEngine\Command; use OCA\WorkflowEngine\Helper\ScopeContext; @@ -43,11 +44,11 @@ protected function configure() { } protected function mappedScope(string $scope): int { - static $scopes = [ + return match($scope) { 'admin' => IManager::SCOPE_ADMIN, 'user' => IManager::SCOPE_USER, - ]; - return $scopes[$scope] ?? -1; + default => -1, + }; } protected function execute(InputInterface $input, OutputInterface $output): int { diff --git a/apps/workflowengine/lib/Manager.php b/apps/workflowengine/lib/Manager.php index e426f96ac4aeb..a0f479c437092 100644 --- a/apps/workflowengine/lib/Manager.php +++ b/apps/workflowengine/lib/Manager.php @@ -65,6 +65,9 @@ class Manager implements IManager { /** @var CappedMemoryCache */ protected CappedMemoryCache $operationsByScope; + /** @var array, ScopeContext[]> $scopesByOperation */ + private array $scopesByOperation = []; + public function __construct( protected readonly IDBConnection $connection, protected readonly ContainerInterface $container, @@ -128,10 +131,8 @@ public function getAllConfiguredEvents() { * @return ScopeContext[] */ public function getAllConfiguredScopesForOperation(string $operationClass): array { - /** @var array, ScopeContext[]> $scopesByOperation */ - static $scopesByOperation = []; - if (isset($scopesByOperation[$operationClass])) { - return $scopesByOperation[$operationClass]; + if (isset($this->scopesByOperation[$operationClass])) { + return $this->scopesByOperation[$operationClass]; } try { @@ -152,7 +153,7 @@ public function getAllConfiguredScopesForOperation(string $operationClass): arra $query->setParameters(['operationClass' => $operationClass]); $result = $query->executeQuery(); - $scopesByOperation[$operationClass] = []; + $this->scopesByOperation[$operationClass] = []; while ($row = $result->fetchAssociative()) { $scope = new ScopeContext($row['type'], $row['value']); @@ -160,10 +161,10 @@ public function getAllConfiguredScopesForOperation(string $operationClass): arra continue; } - $scopesByOperation[$operationClass][$scope->getHash()] = $scope; + $this->scopesByOperation[$operationClass][$scope->getHash()] = $scope; } - return $scopesByOperation[$operationClass]; + return $this->scopesByOperation[$operationClass]; } public function getAllOperations(ScopeContext $scopeContext): array { From 4267304ca733d9c5dc3d1602fa93e085ff798617 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=B4me=20Chilliet?= Date: Fri, 13 Mar 2026 13:10:54 +0100 Subject: [PATCH 09/17] fix: Remove static vars from core classes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Côme Chilliet --- core/Command/Db/Migrations/GenerateCommand.php | 4 ++-- lib/private/Accounts/AccountManager.php | 2 +- lib/private/App/PlatformRepository.php | 8 ++++---- lib/private/Files/Cache/Storage.php | 8 +------- lib/private/Files/SetupManager.php | 9 +++++---- lib/private/Files/Storage/Common.php | 9 +++++---- lib/private/Server.php | 4 +--- lib/private/Setup.php | 6 +++--- 8 files changed, 22 insertions(+), 28 deletions(-) diff --git a/core/Command/Db/Migrations/GenerateCommand.php b/core/Command/Db/Migrations/GenerateCommand.php index a75280fa8b125..cec93146d7798 100644 --- a/core/Command/Db/Migrations/GenerateCommand.php +++ b/core/Command/Db/Migrations/GenerateCommand.php @@ -23,7 +23,7 @@ use Symfony\Component\Console\Question\ConfirmationQuestion; class GenerateCommand extends Command implements CompletionAwareInterface { - protected static $_templateSimple + private const string TEMPLATE = 'getMigrationsDirectory(); $this->ensureMigrationDirExists($dir); diff --git a/lib/private/Accounts/AccountManager.php b/lib/private/Accounts/AccountManager.php index 373a697a327a5..102e6a8b9cb34 100644 --- a/lib/private/Accounts/AccountManager.php +++ b/lib/private/Accounts/AccountManager.php @@ -368,7 +368,7 @@ protected function addMissingDefaultValues(array $userData, array $defaultUserDa } protected function updateVerificationStatus(IAccount $updatedAccount, array $oldData): void { - static $propertiesVerifiableByLookupServer = [ + $propertiesVerifiableByLookupServer = [ self::PROPERTY_TWITTER, self::PROPERTY_FEDIVERSE, self::PROPERTY_WEBSITE, diff --git a/lib/private/App/PlatformRepository.php b/lib/private/App/PlatformRepository.php index faed8b07feb50..1a1e27783a1dc 100644 --- a/lib/private/App/PlatformRepository.php +++ b/lib/private/App/PlatformRepository.php @@ -127,7 +127,7 @@ public function findLibrary(string $name): ?string { return null; } - private static string $modifierRegex = '[._-]?(?:(stable|beta|b|RC|alpha|a|patch|pl|p)(?:[.-]?(\d+))?)?([.-]?dev)?'; + private const string MODIFIER_REGEX = '[._-]?(?:(stable|beta|b|RC|alpha|a|patch|pl|p)(?:[.-]?(\d+))?)?([.-]?dev)?'; /** * Normalizes a version string to be able to perform comparisons on it @@ -154,16 +154,16 @@ public function normalizeVersion(string $version, ?string $fullVersion = null): return 'dev-' . substr($version, 4); } // match classical versioning - if (preg_match('{^v?(\d{1,3})(\.\d+)?(\.\d+)?(\.\d+)?' . self::$modifierRegex . '$}i', $version, $matches)) { + if (preg_match('{^v?(\d{1,3})(\.\d+)?(\.\d+)?(\.\d+)?' . self::MODIFIER_REGEX . '$}i', $version, $matches)) { $version = $matches[1] . (!empty($matches[2]) ? $matches[2] : '.0') . (!empty($matches[3]) ? $matches[3] : '.0') . (!empty($matches[4]) ? $matches[4] : '.0'); $index = 5; - } elseif (preg_match('{^v?(\d{4}(?:[.:-]?\d{2}){1,6}(?:[.:-]?\d{1,3})?)' . self::$modifierRegex . '$}i', $version, $matches)) { // match date-based versioning + } elseif (preg_match('{^v?(\d{4}(?:[.:-]?\d{2}){1,6}(?:[.:-]?\d{1,3})?)' . self::MODIFIER_REGEX . '$}i', $version, $matches)) { // match date-based versioning $version = preg_replace('{\D}', '-', $matches[1]); $index = 2; - } elseif (preg_match('{^v?(\d{4,})(\.\d+)?(\.\d+)?(\.\d+)?' . self::$modifierRegex . '$}i', $version, $matches)) { + } elseif (preg_match('{^v?(\d{4,})(\.\d+)?(\.\d+)?(\.\d+)?' . self::MODIFIER_REGEX . '$}i', $version, $matches)) { $version = $matches[1] . (!empty($matches[2]) ? $matches[2] : '.0') . (!empty($matches[3]) ? $matches[3] : '.0') diff --git a/lib/private/Files/Cache/Storage.php b/lib/private/Files/Cache/Storage.php index 49b24ec8b34f9..5417095f44bee 100644 --- a/lib/private/Files/Cache/Storage.php +++ b/lib/private/Files/Cache/Storage.php @@ -28,18 +28,12 @@ * @package OC\Files\Cache */ class Storage { - private static ?StorageGlobal $globalCache = null; - private string $storageId; private int $numericId; public static function getGlobalCache(): StorageGlobal { - if (is_null(self::$globalCache)) { - self::$globalCache = new StorageGlobal(Server::get(IDBConnection::class)); - } - - return self::$globalCache; + return Server::get(StorageGlobal::class); } /** diff --git a/lib/private/Files/SetupManager.php b/lib/private/Files/SetupManager.php index 5cd32fdfe0e08..ce6e479f6522f 100644 --- a/lib/private/Files/SetupManager.php +++ b/lib/private/Files/SetupManager.php @@ -95,6 +95,8 @@ class SetupManager implements ISetupManager { private const SETUP_WITH_CHILDREN = 1; private const SETUP_WITHOUT_CHILDREN = 0; + private bool $updatingProviders = false; + public function __construct( private IEventLogger $eventLogger, private MountProviderCollection $mountProviderCollection, @@ -245,11 +247,10 @@ private function updateNonAuthoritativeProviders(IUser $user): void { } // prevent recursion loop from when getting mounts from providers ends up setting up the filesystem - static $updatingProviders = false; - if ($updatingProviders) { + if ($this->updatingProviders) { return; } - $updatingProviders = true; + $this->updatingProviders = true; $providers = $this->mountProviderCollection->getProviders(); $nonAuthoritativeProviders = array_filter( @@ -265,7 +266,7 @@ private function updateNonAuthoritativeProviders(IUser $user): void { $this->userMountCache->registerMounts($user, $mount, $providerNames); $this->usersMountsUpdated[$user->getUID()] = true; - $updatingProviders = false; + $this->updatingProviders = false; } #[Override] diff --git a/lib/private/Files/Storage/Common.php b/lib/private/Files/Storage/Common.php index 696232da64fa0..bb6848bc4fb11 100644 --- a/lib/private/Files/Storage/Common.php +++ b/lib/private/Files/Storage/Common.php @@ -74,6 +74,8 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage, private ?LoggerInterface $logger = null; private ?IFilenameValidator $filenameValidator = null; + private ?CacheDependencies $cacheDependencies = null; + public function __construct(array $parameters) { } @@ -304,11 +306,10 @@ public function hasUpdated(string $path, int $time): bool { } protected function getCacheDependencies(): CacheDependencies { - static $dependencies = null; - if (!$dependencies) { - $dependencies = Server::get(CacheDependencies::class); + if ($this->cacheDependencies === null) { + $this->cacheDependencies = Server::get(CacheDependencies::class); } - return $dependencies; + return $this->cacheDependencies; } public function getCache(string $path = '', ?IStorage $storage = null): ICache { diff --git a/lib/private/Server.php b/lib/private/Server.php index 28ce2589f637c..729a60efd04fe 100644 --- a/lib/private/Server.php +++ b/lib/private/Server.php @@ -60,7 +60,6 @@ use OC\Files\Config\UserMountCacheListener; use OC\Files\Conversion\ConversionManager; use OC\Files\FilenameValidator; -use OC\Files\Filesystem; use OC\Files\Lock\LockManager; use OC\Files\Mount\CacheMountProvider; use OC\Files\Mount\LocalHomeMountProvider; @@ -440,12 +439,11 @@ public function __construct( }); $this->registerAlias(IFileAccess::class, FileAccess::class); $this->registerService('RootFolder', function (ContainerInterface $c) { - $manager = Filesystem::getMountManager(); $view = new View(); /** @var IUserSession $userSession */ $userSession = $c->get(IUserSession::class); $root = new Root( - $manager, + $c->get(\OC\Files\Mount\Manager::class), $view, $userSession->getUser(), $c->get(IUserMountCache::class), diff --git a/lib/private/Setup.php b/lib/private/Setup.php index efdbd1cfd6c57..7ba40f6578b97 100644 --- a/lib/private/Setup.php +++ b/lib/private/Setup.php @@ -72,7 +72,7 @@ public function __construct( $this->l10n = $l10nFactory->get('lib'); } - protected static array $dbSetupClasses = [ + private const array DB_SETUP_CLASSES = [ 'mysql' => MySQL::class, 'pgsql' => PostgreSQL::class, 'oci' => OCI::class, @@ -334,13 +334,13 @@ public function install(array $options, ?IOutput $output = null): array { $options['directory'] = \OC::$SERVERROOT . '/data'; } - if (!isset(self::$dbSetupClasses[$dbType])) { + if (!isset(self::DB_SETUP_CLASSES[$dbType])) { $dbType = 'sqlite'; } $dataDir = htmlspecialchars_decode($options['directory']); - $class = self::$dbSetupClasses[$dbType]; + $class = self::DB_SETUP_CLASSES[$dbType]; /** @var AbstractDatabase $dbSetup */ $dbSetup = new $class($l, $this->config, $this->logger, $this->random); $error = array_merge($error, $dbSetup->validate($options)); From 7d4f09054b2e343d94a2f1f30d3bcb075a665bb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=B4me=20Chilliet?= Date: Tue, 17 Mar 2026 15:15:13 +0100 Subject: [PATCH 10/17] fixup! chore: Remove types from const properties MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Côme Chilliet --- lib/private/TextProcessing/Manager.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/private/TextProcessing/Manager.php b/lib/private/TextProcessing/Manager.php index b6021246c0199..1aedcc891d2ad 100644 --- a/lib/private/TextProcessing/Manager.php +++ b/lib/private/TextProcessing/Manager.php @@ -47,7 +47,7 @@ class Manager implements IManager { /** * @var array */ - private const array COMPATIBLE_TASK_TYPES = [ + private const COMPATIBLE_TASK_TYPES = [ FreePromptTaskType::class => TextToText::ID, HeadlineTaskType::class => TextToTextHeadline::ID, SummaryTaskType::class => TextToTextSummary::ID, From 39430e8c05e8fd73d419f43d933f12d90e3c5811 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=B4me=20Chilliet?= Date: Tue, 17 Mar 2026 15:15:55 +0100 Subject: [PATCH 11/17] chore: Remove types from const properties for PHP 8.2 compatibility MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Côme Chilliet --- core/Command/Db/Migrations/GenerateCommand.php | 2 +- lib/private/App/PlatformRepository.php | 2 +- lib/private/Setup.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/Command/Db/Migrations/GenerateCommand.php b/core/Command/Db/Migrations/GenerateCommand.php index cec93146d7798..5bc7a3abdf2f8 100644 --- a/core/Command/Db/Migrations/GenerateCommand.php +++ b/core/Command/Db/Migrations/GenerateCommand.php @@ -23,7 +23,7 @@ use Symfony\Component\Console\Question\ConfirmationQuestion; class GenerateCommand extends Command implements CompletionAwareInterface { - private const string TEMPLATE + private const TEMPLATE = 'l10n = $l10nFactory->get('lib'); } - private const array DB_SETUP_CLASSES = [ + private const DB_SETUP_CLASSES = [ 'mysql' => MySQL::class, 'pgsql' => PostgreSQL::class, 'oci' => OCI::class, From 1590222cf14c8fbc02bc3631cfb388a3e0830605 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=B4me=20Chilliet?= Date: Fri, 13 Mar 2026 10:20:10 +0100 Subject: [PATCH 12/17] feat: Add a psalm plugin to forbid static properties and variables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Côme Chilliet --- build/psalm/StaticVarsChecker.php | 54 +++++++++++++++++++++++++++++++ build/psalm/StaticVarsTest.php | 23 +++++++++++++ psalm.xml | 1 + 3 files changed, 78 insertions(+) create mode 100644 build/psalm/StaticVarsChecker.php create mode 100644 build/psalm/StaticVarsTest.php diff --git a/build/psalm/StaticVarsChecker.php b/build/psalm/StaticVarsChecker.php new file mode 100644 index 0000000000000..24d08b45aa8cf --- /dev/null +++ b/build/psalm/StaticVarsChecker.php @@ -0,0 +1,54 @@ +getStmt(); + $statementsSource = $event->getStatementsSource(); + + foreach ($classLike->stmts as $stmt) { + if ($stmt instanceof Property) { + if ($stmt->isStatic()) { + IssueBuffer::maybeAdd( + // ImpureStaticProperty is close enough, all static properties are impure to my eyes + new \Psalm\Issue\ImpureStaticProperty( + 'Static property should not be used as they do not follow requests lifecycle', + new CodeLocation($statementsSource, $stmt), + ) + ); + } + } + } + } + + public static function afterStatementAnalysis(AfterStatementAnalysisEvent $event): ?bool { + $stmt = $event->getStmt(); + if ($stmt instanceof PhpParser\Node\Stmt\Static_) { + IssueBuffer::maybeAdd( + // Same logic + new \Psalm\Issue\ImpureStaticVariable( + 'Static var should not be used as they do not follow requests lifecycle and are hard to reset', + new CodeLocation($event->getStatementsSource(), $stmt), + ) + ); + } + return null; + } +} diff --git a/build/psalm/StaticVarsTest.php b/build/psalm/StaticVarsTest.php new file mode 100644 index 0000000000000..f40ac56ff5144 --- /dev/null +++ b/build/psalm/StaticVarsTest.php @@ -0,0 +1,23 @@ + + From 5a981e613f0975e5971f26b110c767f7156715ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=B4me=20Chilliet?= Date: Tue, 17 Mar 2026 15:55:51 +0100 Subject: [PATCH 13/17] fix: Remove use of static vars in dav application MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Côme Chilliet --- apps/dav/lib/CalDAV/CalDavBackend.php | 6 +++--- apps/dav/lib/CardDAV/CardDavBackend.php | 4 ++-- apps/dav/lib/Search/ContactsSearchProvider.php | 6 +++--- apps/dav/lib/Search/EventsSearchProvider.php | 18 +++++++++--------- apps/dav/lib/Search/TasksSearchProvider.php | 14 +++++++------- 5 files changed, 24 insertions(+), 24 deletions(-) diff --git a/apps/dav/lib/CalDAV/CalDavBackend.php b/apps/dav/lib/CalDAV/CalDavBackend.php index cdf542467c173..32638f6fd1989 100644 --- a/apps/dav/lib/CalDAV/CalDavBackend.php +++ b/apps/dav/lib/CalDAV/CalDavBackend.php @@ -190,7 +190,7 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription ]; /** @var array parameters to index */ - public static array $indexParameters = [ + private const INDEXED_PARAMETERS = [ 'ATTENDEE' => ['CN'], 'ORGANIZER' => ['CN'], ]; @@ -3382,9 +3382,9 @@ public function updateProperties($calendarId, $objectUri, $calendarData, $calend $query->executeStatement(); } - if (array_key_exists($property->name, self::$indexParameters)) { + if (array_key_exists($property->name, self::INDEXED_PARAMETERS)) { $parameters = $property->parameters(); - $indexedParametersForProperty = self::$indexParameters[$property->name]; + $indexedParametersForProperty = self::INDEXED_PARAMETERS[$property->name]; foreach ($parameters as $key => $value) { if (in_array($key, $indexedParametersForProperty)) { diff --git a/apps/dav/lib/CardDAV/CardDavBackend.php b/apps/dav/lib/CardDAV/CardDavBackend.php index 0ca82200735d9..0736456de47ca 100644 --- a/apps/dav/lib/CardDAV/CardDavBackend.php +++ b/apps/dav/lib/CardDAV/CardDavBackend.php @@ -42,7 +42,7 @@ class CardDavBackend implements BackendInterface, SyncSupport { private string $dbCardsPropertiesTable = 'cards_properties'; /** @var array properties to index */ - public static array $indexProperties = [ + private const INDEXED_PROPERTIES = [ 'BDAY', 'UID', 'N', 'FN', 'TITLE', 'ROLE', 'NOTE', 'NICKNAME', 'ORG', 'CATEGORIES', 'EMAIL', 'TEL', 'IMPP', 'ADR', 'URL', 'GEO', 'CLOUD', 'X-SOCIALPROFILE']; @@ -1384,7 +1384,7 @@ protected function updateProperties($addressBookId, $cardUri, $vCardSerialized) ); foreach ($vCard->children() as $property) { - if (!in_array($property->name, self::$indexProperties)) { + if (!in_array($property->name, self::INDEXED_PROPERTIES)) { continue; } $preferred = 0; diff --git a/apps/dav/lib/Search/ContactsSearchProvider.php b/apps/dav/lib/Search/ContactsSearchProvider.php index 158c0d0813e3a..f4a4cde23f44d 100644 --- a/apps/dav/lib/Search/ContactsSearchProvider.php +++ b/apps/dav/lib/Search/ContactsSearchProvider.php @@ -23,14 +23,14 @@ use Sabre\VObject\Reader; class ContactsSearchProvider implements IFilteringProvider { - private static array $searchPropertiesRestricted = [ + private const SEARCH_PROPERTIES_RESTRICTED = [ 'N', 'FN', 'NICKNAME', 'EMAIL', ]; - private static array $searchProperties = [ + private const SEARCH_PROPERTIES = [ 'N', 'FN', 'NICKNAME', @@ -87,7 +87,7 @@ public function search(IUser $user, ISearchQuery $query): SearchResult { $searchResults = $this->backend->searchPrincipalUri( $principalUri, $query->getFilter('term')?->get() ?? '', - $query->getFilter('title-only')?->get() ? self::$searchPropertiesRestricted : self::$searchProperties, + $query->getFilter('title-only')?->get() ? self::SEARCH_PROPERTIES_RESTRICTED : self::SEARCH_PROPERTIES, [ 'limit' => $query->getLimit(), 'offset' => $query->getCursor(), diff --git a/apps/dav/lib/Search/EventsSearchProvider.php b/apps/dav/lib/Search/EventsSearchProvider.php index 9d57586fd84da..b0c59b5a34f0a 100644 --- a/apps/dav/lib/Search/EventsSearchProvider.php +++ b/apps/dav/lib/Search/EventsSearchProvider.php @@ -32,7 +32,7 @@ class EventsSearchProvider extends ACalendarSearchProvider implements IFiltering /** * @var string[] */ - private static $searchProperties = [ + private const SEARCH_PROPERTIES = [ 'SUMMARY', 'LOCATION', 'DESCRIPTION', @@ -44,7 +44,7 @@ class EventsSearchProvider extends ACalendarSearchProvider implements IFiltering /** * @var string[] */ - private static $searchParameters = [ + private const SEARCH_PARAMETERS = [ 'ATTENDEE' => ['CN'], 'ORGANIZER' => ['CN'], ]; @@ -52,7 +52,7 @@ class EventsSearchProvider extends ACalendarSearchProvider implements IFiltering /** * @var string */ - private static $componentType = 'VEVENT'; + private const COMPONENT_TYPE = 'VEVENT'; /** * @inheritDoc @@ -102,9 +102,9 @@ public function search( $searchResults = $this->backend->searchPrincipalUri( $principalUri, $term, - [self::$componentType], - self::$searchProperties, - self::$searchParameters, + [self::COMPONENT_TYPE], + self::SEARCH_PROPERTIES, + self::SEARCH_PARAMETERS, [ 'limit' => $query->getLimit(), 'offset' => $query->getCursor(), @@ -122,9 +122,9 @@ public function search( $attendeeSearchResults = $this->backend->searchPrincipalUri( $principalUri, $personDisplayName, - [self::$componentType], + [self::COMPONENT_TYPE], ['ATTENDEE'], - self::$searchParameters, + self::SEARCH_PARAMETERS, [ 'limit' => $query->getLimit(), 'offset' => $query->getCursor(), @@ -148,7 +148,7 @@ public function search( } } $formattedResults = \array_map(function (array $eventRow) use ($calendarsById, $subscriptionsById): SearchResultEntry { - $component = $this->getPrimaryComponent($eventRow['calendardata'], self::$componentType); + $component = $this->getPrimaryComponent($eventRow['calendardata'], self::COMPONENT_TYPE); $title = (string)($component->SUMMARY ?? $this->l10n->t('Untitled event')); if ($eventRow['calendartype'] === CalDavBackend::CALENDAR_TYPE_CALENDAR) { diff --git a/apps/dav/lib/Search/TasksSearchProvider.php b/apps/dav/lib/Search/TasksSearchProvider.php index 46063cce16d7a..23e4ab3c1fdc5 100644 --- a/apps/dav/lib/Search/TasksSearchProvider.php +++ b/apps/dav/lib/Search/TasksSearchProvider.php @@ -24,7 +24,7 @@ class TasksSearchProvider extends ACalendarSearchProvider { /** * @var string[] */ - private static $searchProperties = [ + private const SEARCH_PROPERTIES = [ 'SUMMARY', 'DESCRIPTION', 'CATEGORIES', @@ -33,12 +33,12 @@ class TasksSearchProvider extends ACalendarSearchProvider { /** * @var string[] */ - private static $searchParameters = []; + private const SEARCH_PARAMETERS = []; /** * @var string */ - private static $componentType = 'VTODO'; + private const COMPONENT_TYPE = 'VTODO'; /** * @inheritDoc @@ -83,9 +83,9 @@ public function search( $searchResults = $this->backend->searchPrincipalUri( $principalUri, $query->getFilter('term')?->get() ?? '', - [self::$componentType], - self::$searchProperties, - self::$searchParameters, + [self::COMPONENT_TYPE], + self::SEARCH_PROPERTIES, + self::SEARCH_PARAMETERS, [ 'limit' => $query->getLimit(), 'offset' => $query->getCursor(), @@ -94,7 +94,7 @@ public function search( ] ); $formattedResults = \array_map(function (array $taskRow) use ($calendarsById, $subscriptionsById):SearchResultEntry { - $component = $this->getPrimaryComponent($taskRow['calendardata'], self::$componentType); + $component = $this->getPrimaryComponent($taskRow['calendardata'], self::COMPONENT_TYPE); $title = (string)($component->SUMMARY ?? $this->l10n->t('Untitled task')); if ($taskRow['calendartype'] === CalDavBackend::CALENDAR_TYPE_CALENDAR) { From 68f7dbe8ff4035a645886afdc4d558bc6e68bc92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=B4me=20Chilliet?= Date: Tue, 17 Mar 2026 16:33:26 +0100 Subject: [PATCH 14/17] fix: Remove unused static var and method in files application MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Côme Chilliet --- apps/files/lib/App.php | 34 ---------------------------------- 1 file changed, 34 deletions(-) diff --git a/apps/files/lib/App.php b/apps/files/lib/App.php index 9e6d35a75383e..0326b670608a7 100644 --- a/apps/files/lib/App.php +++ b/apps/files/lib/App.php @@ -7,43 +7,9 @@ */ namespace OCA\Files; -use OC\NavigationManager; use OCA\Files\Service\ChunkedUploadConfig; -use OCP\App\IAppManager; -use OCP\EventDispatcher\IEventDispatcher; -use OCP\IConfig; -use OCP\IGroupManager; -use OCP\INavigationManager; -use OCP\IURLGenerator; -use OCP\IUserSession; -use OCP\L10N\IFactory; -use OCP\Server; -use Psr\Log\LoggerInterface; class App { - private static ?INavigationManager $navigationManager = null; - - /** - * Returns the app's navigation manager - */ - public static function getNavigationManager(): INavigationManager { - // TODO: move this into a service in the Application class - if (self::$navigationManager === null) { - self::$navigationManager = new NavigationManager( - Server::get(IAppManager::class), - Server::get(IUrlGenerator::class), - Server::get(IFactory::class), - Server::get(IUserSession::class), - Server::get(IGroupManager::class), - Server::get(IConfig::class), - Server::get(LoggerInterface::class), - Server::get(IEventDispatcher::class), - ); - self::$navigationManager->clear(false); - } - return self::$navigationManager; - } - public static function extendJsConfig($settings): void { $appConfig = json_decode($settings['array']['oc_appconfig'], true); From 4d0d1ad3dec032a4ff9ef4107273946e8d93105c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=B4me=20Chilliet?= Date: Tue, 17 Mar 2026 16:34:07 +0100 Subject: [PATCH 15/17] fix: Remove static vars usage in user_ldap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are still some left, harder to remove. Signed-off-by: Côme Chilliet --- apps/user_ldap/lib/Configuration.php | 6 +----- apps/user_ldap/lib/Mapping/UserMapping.php | 13 +++++-------- apps/user_ldap/tests/Mapping/UserMappingTest.php | 3 ++- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/apps/user_ldap/lib/Configuration.php b/apps/user_ldap/lib/Configuration.php index 42eaa464d5f7a..f09970ea75ac9 100644 --- a/apps/user_ldap/lib/Configuration.php +++ b/apps/user_ldap/lib/Configuration.php @@ -444,13 +444,9 @@ protected function getSystemValue(string $varName): string { } protected function getValue(string $varName): string { - static $defaults; - if (is_null($defaults)) { - $defaults = $this->getDefaults(); - } return Server::get(IConfig::class)->getAppValue('user_ldap', $this->configPrefix . $varName, - $defaults[$varName]); + $this->getDefaults()[$varName]); } /** diff --git a/apps/user_ldap/lib/Mapping/UserMapping.php b/apps/user_ldap/lib/Mapping/UserMapping.php index b2c97df3f9c8b..f48d76f722b51 100644 --- a/apps/user_ldap/lib/Mapping/UserMapping.php +++ b/apps/user_ldap/lib/Mapping/UserMapping.php @@ -1,10 +1,13 @@ assertion->createUserIsLegit(); } catch (HintException $e) { - static $isProvisioningApi = null; - - if ($isProvisioningApi === null) { - $request = Server::get(IRequest::class); - $isProvisioningApi = \preg_match(self::PROV_API_REGEX, $request->getRequestUri()) === 1; - } - if ($isProvisioningApi) { + if (\preg_match(self::PROV_API_REGEX, $this->request->getRequestUri()) === 1) { // only throw when prov API is being used, since functionality // should not break for end users (e.g. when sharing). // On direct API usage, e.g. on users page, this is desired. diff --git a/apps/user_ldap/tests/Mapping/UserMappingTest.php b/apps/user_ldap/tests/Mapping/UserMappingTest.php index b352e4e3b0a1c..cf20430fd104b 100644 --- a/apps/user_ldap/tests/Mapping/UserMappingTest.php +++ b/apps/user_ldap/tests/Mapping/UserMappingTest.php @@ -12,6 +12,7 @@ use OCP\IAppConfig; use OCP\ICacheFactory; use OCP\IDBConnection; +use OCP\IRequest; use OCP\Support\Subscription\IAssertion; /** @@ -23,6 +24,6 @@ #[\PHPUnit\Framework\Attributes\Group(name: 'DB')] class UserMappingTest extends AbstractMappingTestCase { public function getMapper(IDBConnection $dbMock, ICacheFactory $cacheFactory, IAppConfig $appConfig): UserMapping { - return new UserMapping($dbMock, $cacheFactory, $appConfig, true, $this->createMock(IAssertion::class)); + return new UserMapping($dbMock, $cacheFactory, $appConfig, true, $this->createMock(IAssertion::class), $this->createMock(IRequest::class)); } } From 02d74c74278add162d8db1e455c5063924e5c77b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=B4me=20Chilliet?= Date: Tue, 17 Mar 2026 16:34:44 +0100 Subject: [PATCH 16/17] fix: Remove static vars in trashbin, versions and storages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Côme Chilliet --- .../lib/Service/BackendService.php | 10 ++++---- .../lib/Command/RestoreAllFiles.php | 6 ++--- apps/files_versions/lib/Storage.php | 14 +++++------ lib/private/Files/Cache/SearchBuilder.php | 24 +++++++++---------- 4 files changed, 27 insertions(+), 27 deletions(-) diff --git a/apps/files_external/lib/Service/BackendService.php b/apps/files_external/lib/Service/BackendService.php index 271ffa7695ff5..322b1ed4dfb08 100644 --- a/apps/files_external/lib/Service/BackendService.php +++ b/apps/files_external/lib/Service/BackendService.php @@ -54,7 +54,8 @@ class BackendService { /** @var callable[] */ private $configHandlerLoaders = []; - private $configHandlers = []; + private array $configHandlers = []; + private bool $eventSent = false; public function __construct( protected readonly IAppConfig $appConfig, @@ -71,14 +72,13 @@ public function registerBackendProvider(IBackendProvider $provider) { $this->backendProviders[] = $provider; } - private function callForRegistrations() { - static $eventSent = false; - if (!$eventSent) { + private function callForRegistrations(): void { + if (!$this->eventSent) { Server::get(IEventDispatcher::class)->dispatch( 'OCA\\Files_External::loadAdditionalBackends', new GenericEvent() ); - $eventSent = true; + $this->eventSent = true; } } diff --git a/apps/files_trashbin/lib/Command/RestoreAllFiles.php b/apps/files_trashbin/lib/Command/RestoreAllFiles.php index 938a98b36bfdf..db926bbc40090 100644 --- a/apps/files_trashbin/lib/Command/RestoreAllFiles.php +++ b/apps/files_trashbin/lib/Command/RestoreAllFiles.php @@ -29,7 +29,7 @@ class RestoreAllFiles extends Base { private const SCOPE_USER = 1; private const SCOPE_GROUPFOLDERS = 2; - private static array $SCOPE_MAP = [ + private const SCOPE_MAP = [ 'user' => self::SCOPE_USER, 'groupfolders' => self::SCOPE_GROUPFOLDERS, 'all' => self::SCOPE_ALL @@ -218,8 +218,8 @@ protected function parseArgs(InputInterface $input): array { } protected function parseScope(string $scope): int { - if (isset(self::$SCOPE_MAP[$scope])) { - return self::$SCOPE_MAP[$scope]; + if (isset(self::SCOPE_MAP[$scope])) { + return self::SCOPE_MAP[$scope]; } throw new InvalidOptionException("Invalid scope '$scope'"); diff --git a/apps/files_versions/lib/Storage.php b/apps/files_versions/lib/Storage.php index fe9f91534fa01..0c16693a6f5f8 100644 --- a/apps/files_versions/lib/Storage.php +++ b/apps/files_versions/lib/Storage.php @@ -60,7 +60,7 @@ class Storage { private static $sourcePathAndUser = []; - private static $max_versions_per_interval = [ + private const MAX_VERSIONS_PER_INTERVAL = [ //first 10sec, one version every 2sec 1 => ['intervalEndsAfter' => 10, 'step' => 2], //next minute, one version every 10sec @@ -763,11 +763,11 @@ protected static function getAutoExpireList($time, $versions) { $toDelete = []; // versions we want to delete $interval = 1; - $step = Storage::$max_versions_per_interval[$interval]['step']; - if (Storage::$max_versions_per_interval[$interval]['intervalEndsAfter'] === -1) { + $step = Storage::MAX_VERSIONS_PER_INTERVAL[$interval]['step']; + if (Storage::MAX_VERSIONS_PER_INTERVAL[$interval]['intervalEndsAfter'] === -1) { $nextInterval = -1; } else { - $nextInterval = $time - Storage::$max_versions_per_interval[$interval]['intervalEndsAfter']; + $nextInterval = $time - Storage::MAX_VERSIONS_PER_INTERVAL[$interval]['intervalEndsAfter']; } $firstVersion = reset($versions); @@ -797,12 +797,12 @@ protected static function getAutoExpireList($time, $versions) { $newInterval = false; // version checked so we can move to the next one } else { // time to move on to the next interval $interval++; - $step = Storage::$max_versions_per_interval[$interval]['step']; + $step = Storage::MAX_VERSIONS_PER_INTERVAL[$interval]['step']; $nextVersion = $prevTimestamp - $step; - if (Storage::$max_versions_per_interval[$interval]['intervalEndsAfter'] === -1) { + if (Storage::MAX_VERSIONS_PER_INTERVAL[$interval]['intervalEndsAfter'] === -1) { $nextInterval = -1; } else { - $nextInterval = $time - Storage::$max_versions_per_interval[$interval]['intervalEndsAfter']; + $nextInterval = $time - Storage::MAX_VERSIONS_PER_INTERVAL[$interval]['intervalEndsAfter']; } $newInterval = true; // we changed the interval -> check same version with new interval } diff --git a/lib/private/Files/Cache/SearchBuilder.php b/lib/private/Files/Cache/SearchBuilder.php index 4f012c8f2087c..ca9f7b1425674 100644 --- a/lib/private/Files/Cache/SearchBuilder.php +++ b/lib/private/Files/Cache/SearchBuilder.php @@ -24,7 +24,7 @@ */ class SearchBuilder { /** @var array */ - protected static $searchOperatorMap = [ + private const SEARCH_OPERATOR_MAP = [ ISearchComparison::COMPARE_LIKE => 'iLike', ISearchComparison::COMPARE_LIKE_CASE_SENSITIVE => 'like', ISearchComparison::COMPARE_EQUAL => 'eq', @@ -37,7 +37,7 @@ class SearchBuilder { ]; /** @var array */ - protected static $searchOperatorNegativeMap = [ + private const SEARCH_OPERATOR_NEGATIVE_MAP = [ ISearchComparison::COMPARE_LIKE => 'notLike', ISearchComparison::COMPARE_LIKE_CASE_SENSITIVE => 'notLike', ISearchComparison::COMPARE_EQUAL => 'neq', @@ -50,7 +50,7 @@ class SearchBuilder { ]; /** @var array */ - protected static $fieldTypes = [ + private const FIELD_TYPES = [ 'mimetype' => 'string', 'mtime' => 'integer', 'name' => 'string', @@ -69,14 +69,14 @@ class SearchBuilder { ]; /** @var array */ - protected static $paramTypeMap = [ + private const PARAM_TYPE_MAP = [ 'string' => IQueryBuilder::PARAM_STR, 'integer' => IQueryBuilder::PARAM_INT, 'boolean' => IQueryBuilder::PARAM_BOOL, ]; /** @var array */ - protected static $paramArrayTypeMap = [ + private const PARAM_ARRAY_TYPE_MAP = [ 'string' => IQueryBuilder::PARAM_STR_ARRAY, 'integer' => IQueryBuilder::PARAM_INT_ARRAY, 'boolean' => IQueryBuilder::PARAM_INT_ARRAY, @@ -134,7 +134,7 @@ public function searchOperatorToDBExpr( case ISearchBinaryOperator::OPERATOR_NOT: $negativeOperator = $operator->getArguments()[0]; if ($negativeOperator instanceof ISearchComparison) { - return $this->searchComparisonToDBExpr($builder, $negativeOperator, self::$searchOperatorNegativeMap, $metadataQuery); + return $this->searchComparisonToDBExpr($builder, $negativeOperator, self::SEARCH_OPERATOR_NEGATIVE_MAP, $metadataQuery); } else { throw new \InvalidArgumentException('Binary operators inside "not" is not supported'); } @@ -147,7 +147,7 @@ public function searchOperatorToDBExpr( throw new \InvalidArgumentException('Invalid operator type: ' . $operator->getType()); } } elseif ($operator instanceof ISearchComparison) { - return $this->searchComparisonToDBExpr($builder, $operator, self::$searchOperatorMap, $metadataQuery); + return $this->searchComparisonToDBExpr($builder, $operator, self::SEARCH_OPERATOR_MAP, $metadataQuery); } else { throw new \InvalidArgumentException('Invalid operator type: ' . get_class($operator)); } @@ -193,7 +193,7 @@ private function getOperatorFieldAndValue(ISearchComparison $operator): array { * @return list{string, ParamValue, string, string} */ private function getOperatorFieldAndValueInner(string $field, mixed $value, string $type, bool $pathEqHash): array { - $paramType = self::$fieldTypes[$field]; + $paramType = self::FIELD_TYPES[$field]; if ($type === ISearchComparison::COMPARE_IN) { $resultField = $field; $values = []; @@ -263,10 +263,10 @@ private function validateComparison(ISearchComparison $operator) { 'upload_time' => ['eq', 'gt', 'lt', 'gte', 'lte'], ]; - if (!isset(self::$fieldTypes[$operator->getField()])) { + if (!isset(self::FIELD_TYPES[$operator->getField()])) { throw new \InvalidArgumentException('Unsupported comparison field ' . $operator->getField()); } - $type = self::$fieldTypes[$operator->getField()]; + $type = self::FIELD_TYPES[$operator->getField()]; if ($operator->getType() === ISearchComparison::COMPARE_IN) { if (!is_array($operator->getValue())) { throw new \InvalidArgumentException('Invalid type for field ' . $operator->getField()); @@ -317,9 +317,9 @@ private function getParameterForValue(IQueryBuilder $builder, $value, string $pa $value = $value->getTimestamp(); } if (is_array($value)) { - $type = self::$paramArrayTypeMap[$paramType]; + $type = self::PARAM_ARRAY_TYPE_MAP[$paramType]; } else { - $type = self::$paramTypeMap[$paramType]; + $type = self::PARAM_TYPE_MAP[$paramType]; } return $builder->createNamedParameter($value, $type); } From 4620c0f7b9d55306060692bb390e0f36a991c414 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=B4me=20Chilliet?= Date: Tue, 17 Mar 2026 16:35:10 +0100 Subject: [PATCH 17/17] fix: Remove a static var usage in encryption application MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Côme Chilliet --- apps/encryption/lib/Services/PassphraseService.php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/apps/encryption/lib/Services/PassphraseService.php b/apps/encryption/lib/Services/PassphraseService.php index bdcc3f1108ae1..592a85572db4f 100644 --- a/apps/encryption/lib/Services/PassphraseService.php +++ b/apps/encryption/lib/Services/PassphraseService.php @@ -21,9 +21,8 @@ use Psr\Log\LoggerInterface; class PassphraseService { - /** @var array */ - private static array $passwordResetUsers = []; + private array $passwordResetUsers = []; public function __construct( private Util $util, @@ -39,9 +38,9 @@ public function __construct( public function setProcessingReset(string $uid, bool $processing = true): void { if ($processing) { - self::$passwordResetUsers[$uid] = true; + $this->passwordResetUsers[$uid] = true; } else { - unset(self::$passwordResetUsers[$uid]); + unset($this->passwordResetUsers[$uid]); } } @@ -51,7 +50,7 @@ public function setProcessingReset(string $uid, bool $processing = true): void { public function setPassphraseForUser(string $userId, string $password, ?string $recoveryPassword = null): bool { // if we are in the process to resetting a user password, we have nothing // to do here - if (isset(self::$passwordResetUsers[$userId])) { + if (isset($this->passwordResetUsers[$userId])) { return true; }