diff --git a/apps/files_external/lib/Service/BackendService.php b/apps/files_external/lib/Service/BackendService.php index 271ffa7695ff5..9d42fb22a4626 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,14 @@ public function registerBackendProvider(IBackendProvider $provider) { $this->backendProviders[] = $provider; } - private function callForRegistrations() { - static $eventSent = false; - if (!$eventSent) { + private function callForRegistrations(): void { + $instance = Server::get(self::class); + if (!$instance->eventSent) { Server::get(IEventDispatcher::class)->dispatch( 'OCA\\Files_External::loadAdditionalBackends', new GenericEvent() ); - $eventSent = true; + $instance->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/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 @@ +} $required */ $required = require __DIR__ . '/installed.php'; self::$installed = $required; diff --git a/lib/composer/composer/installed.json b/lib/composer/composer/installed.json index f20a6c47c6d4f..d8ad3e7828fca 100644 --- a/lib/composer/composer/installed.json +++ b/lib/composer/composer/installed.json @@ -1,5 +1,68 @@ { - "packages": [], - "dev": false, - "dev-package-names": [] + "packages": [ + { + "name": "bamarni/composer-bin-plugin", + "version": "1.9.1", + "version_normalized": "1.9.1.0", + "source": { + "type": "git", + "url": "https://github.com/bamarni/composer-bin-plugin.git", + "reference": "641d0663f5ac270b1aeec4337b7856f76204df47" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/bamarni/composer-bin-plugin/zipball/641d0663f5ac270b1aeec4337b7856f76204df47", + "reference": "641d0663f5ac270b1aeec4337b7856f76204df47", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^2.0", + "php": "^7.2.5 || ^8.0" + }, + "require-dev": { + "composer/composer": "^2.2.26", + "ext-json": "*", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.8 || ^2.0", + "phpstan/phpstan-phpunit": "^1.1 || ^2.0", + "phpunit/phpunit": "^8.5 || ^9.6 || ^10.0", + "symfony/console": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0", + "symfony/finder": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0", + "symfony/process": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0" + }, + "time": "2026-02-04T10:18:12+00:00", + "type": "composer-plugin", + "extra": { + "class": "Bamarni\\Composer\\Bin\\BamarniBinPlugin" + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Bamarni\\Composer\\Bin\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "No conflicts for your bin dependencies", + "keywords": [ + "composer", + "conflict", + "dependency", + "executable", + "isolation", + "tool" + ], + "support": { + "issues": "https://github.com/bamarni/composer-bin-plugin/issues", + "source": "https://github.com/bamarni/composer-bin-plugin/tree/1.9.1" + }, + "install-path": "../bamarni/composer-bin-plugin" + } + ], + "dev": true, + "dev-package-names": [ + "bamarni/composer-bin-plugin" + ] } diff --git a/lib/composer/composer/installed.php b/lib/composer/composer/installed.php index 87357f5e32faa..5041dc099a354 100644 --- a/lib/composer/composer/installed.php +++ b/lib/composer/composer/installed.php @@ -3,21 +3,30 @@ 'name' => '__root__', 'pretty_version' => 'dev-master', 'version' => 'dev-master', - 'reference' => '671cec33f134e670bb21c5e3c49c685bd78fc339', + 'reference' => '91ba91a9d21106ee519f065d6feea2f8f757651c', 'type' => 'library', 'install_path' => __DIR__ . '/../../../', 'aliases' => array(), - 'dev' => false, + 'dev' => true, ), 'versions' => array( '__root__' => array( 'pretty_version' => 'dev-master', 'version' => 'dev-master', - 'reference' => '671cec33f134e670bb21c5e3c49c685bd78fc339', + 'reference' => '91ba91a9d21106ee519f065d6feea2f8f757651c', 'type' => 'library', 'install_path' => __DIR__ . '/../../../', 'aliases' => array(), 'dev_requirement' => false, ), + 'bamarni/composer-bin-plugin' => array( + 'pretty_version' => '1.9.1', + 'version' => '1.9.1.0', + 'reference' => '641d0663f5ac270b1aeec4337b7856f76204df47', + 'type' => 'composer-plugin', + 'install_path' => __DIR__ . '/../bamarni/composer-bin-plugin', + 'aliases' => array(), + 'dev_requirement' => true, + ), ), ); 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); } diff --git a/lib/private/Memcache/Memcached.php b/lib/private/Memcache/Memcached.php index 044a0fccd2512..dcd605d78d7f6 100644 --- a/lib/private/Memcache/Memcached.php +++ b/lib/private/Memcache/Memcached.php @@ -7,73 +7,18 @@ */ namespace OC\Memcache; -use OC\SystemConfig; -use OCP\HintException; -use OCP\IConfig; use OCP\IMemcache; -use OCP\Server; class Memcached extends Cache implements IMemcache { use CASTrait; - /** - * @var \Memcached $cache - */ - private static $cache = null; + private \Memcached $cache; use CADTrait; public function __construct($prefix = '') { parent::__construct($prefix); - if (is_null(self::$cache)) { - self::$cache = new \Memcached(); - - $defaultOptions = [ - \Memcached::OPT_CONNECT_TIMEOUT => 50, - \Memcached::OPT_RETRY_TIMEOUT => 50, - \Memcached::OPT_SEND_TIMEOUT => 50, - \Memcached::OPT_RECV_TIMEOUT => 50, - \Memcached::OPT_POLL_TIMEOUT => 50, - - // Enable compression - \Memcached::OPT_COMPRESSION => true, - - // Turn on consistent hashing - \Memcached::OPT_LIBKETAMA_COMPATIBLE => true, - - // Enable Binary Protocol - \Memcached::OPT_BINARY_PROTOCOL => true, - ]; - /** - * By default enable igbinary serializer if available - * - * Psalm checks depend on if igbinary is installed or not with memcached - * @psalm-suppress RedundantCondition - * @psalm-suppress TypeDoesNotContainType - */ - if (\Memcached::HAVE_IGBINARY) { - $defaultOptions[\Memcached::OPT_SERIALIZER] - = \Memcached::SERIALIZER_IGBINARY; - } - $options = Server::get(IConfig::class)->getSystemValue('memcached_options', []); - if (is_array($options)) { - $options = $options + $defaultOptions; - self::$cache->setOptions($options); - } else { - throw new HintException("Expected 'memcached_options' config to be an array, got $options"); - } - - $servers = Server::get(SystemConfig::class)->getValue('memcached_servers'); - if (!$servers) { - $server = Server::get(SystemConfig::class)->getValue('memcached_server'); - if ($server) { - $servers = [$server]; - } else { - $servers = [['localhost', 11211]]; - } - } - self::$cache->addServers($servers); - } + $this->cache = \OCP\Server::get(MemcachedFactory::class)->getInstance(); } /** @@ -84,8 +29,8 @@ protected function getNameSpace() { } public function get($key) { - $result = self::$cache->get($this->getNameSpace() . $key); - if ($result === false && self::$cache->getResultCode() === \Memcached::RES_NOTFOUND) { + $result = $this->cache->get($this->getNameSpace() . $key); + if ($result === false && $this->cache->getResultCode() === \Memcached::RES_NOTFOUND) { return null; } else { return $result; @@ -94,26 +39,26 @@ public function get($key) { public function set($key, $value, $ttl = 0) { if ($ttl > 0) { - $result = self::$cache->set($this->getNameSpace() . $key, $value, $ttl); + $result = $this->cache->set($this->getNameSpace() . $key, $value, $ttl); } else { - $result = self::$cache->set($this->getNameSpace() . $key, $value); + $result = $this->cache->set($this->getNameSpace() . $key, $value); } return $result || $this->isSuccess(); } public function hasKey($key) { - self::$cache->get($this->getNameSpace() . $key); - return self::$cache->getResultCode() === \Memcached::RES_SUCCESS; + $this->cache->get($this->getNameSpace() . $key); + return $this->cache->getResultCode() === \Memcached::RES_SUCCESS; } public function remove($key) { - $result = self::$cache->delete($this->getNameSpace() . $key); - return $result || $this->isSuccess() || self::$cache->getResultCode() === \Memcached::RES_NOTFOUND; + $result = $this->cache->delete($this->getNameSpace() . $key); + return $result || $this->isSuccess() || $this->cache->getResultCode() === \Memcached::RES_NOTFOUND; } public function clear($prefix = '') { // Newer Memcached doesn't like getAllKeys(), flush everything - self::$cache->flush(); + $this->cache->flush(); return true; } @@ -126,7 +71,7 @@ public function clear($prefix = '') { * @return bool */ public function add($key, $value, $ttl = 0) { - $result = self::$cache->add($this->getPrefix() . $key, $value, $ttl); + $result = $this->cache->add($this->getPrefix() . $key, $value, $ttl); return $result || $this->isSuccess(); } @@ -139,9 +84,9 @@ public function add($key, $value, $ttl = 0) { */ public function inc($key, $step = 1) { $this->add($key, 0); - $result = self::$cache->increment($this->getPrefix() . $key, $step); + $result = $this->cache->increment($this->getPrefix() . $key, $step); - if (self::$cache->getResultCode() !== \Memcached::RES_SUCCESS) { + if ($this->cache->getResultCode() !== \Memcached::RES_SUCCESS) { return false; } @@ -156,9 +101,9 @@ public function inc($key, $step = 1) { * @return int | bool */ public function dec($key, $step = 1) { - $result = self::$cache->decrement($this->getPrefix() . $key, $step); + $result = $this->cache->decrement($this->getPrefix() . $key, $step); - if (self::$cache->getResultCode() !== \Memcached::RES_SUCCESS) { + if ($this->cache->getResultCode() !== \Memcached::RES_SUCCESS) { return false; } @@ -170,6 +115,6 @@ public static function isAvailable(): bool { } private function isSuccess(): bool { - return self::$cache->getResultCode() === \Memcached::RES_SUCCESS; + return $this->cache->getResultCode() === \Memcached::RES_SUCCESS; } } diff --git a/lib/private/Memcache/MemcachedFactory.php b/lib/private/Memcache/MemcachedFactory.php new file mode 100644 index 0000000000000..e829c72af65ea --- /dev/null +++ b/lib/private/Memcache/MemcachedFactory.php @@ -0,0 +1,81 @@ +instance === null) { + $this->init(); + } + return $this->instance; + } + + /** @psalm-assert \Memcached $this->instance */ + public function init(): void { + $this->instance = new \Memcached(); + + $defaultOptions = [ + \Memcached::OPT_CONNECT_TIMEOUT => 50, + \Memcached::OPT_RETRY_TIMEOUT => 50, + \Memcached::OPT_SEND_TIMEOUT => 50, + \Memcached::OPT_RECV_TIMEOUT => 50, + \Memcached::OPT_POLL_TIMEOUT => 50, + + // Enable compression + \Memcached::OPT_COMPRESSION => true, + + // Turn on consistent hashing + \Memcached::OPT_LIBKETAMA_COMPATIBLE => true, + + // Enable Binary Protocol + \Memcached::OPT_BINARY_PROTOCOL => true, + ]; + /** + * By default enable igbinary serializer if available + * + * Psalm checks depend on if igbinary is installed or not with memcached + * @psalm-suppress RedundantCondition + * @psalm-suppress TypeDoesNotContainType + */ + if (\Memcached::HAVE_IGBINARY) { + $defaultOptions[\Memcached::OPT_SERIALIZER] + = \Memcached::SERIALIZER_IGBINARY; + } + $options = Server::get(IConfig::class)->getSystemValue('memcached_options', []); + if (is_array($options)) { + $options = $options + $defaultOptions; + $this->instance->setOptions($options); + } else { + throw new HintException("Expected 'memcached_options' config to be an array, got $options"); + } + + $servers = Server::get(SystemConfig::class)->getValue('memcached_servers'); + if (!$servers) { + $server = Server::get(SystemConfig::class)->getValue('memcached_server'); + if ($server) { + $servers = [$server]; + } else { + $servers = [['localhost', 11211]]; + } + } + $this->instance->addServers($servers); + } +} 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 e24d47f3f0611..729a60efd04fe 100644 --- a/lib/private/Server.php +++ b/lib/private/Server.php @@ -669,10 +669,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'); diff --git a/lib/private/TaskProcessing/Db/Task.php b/lib/private/TaskProcessing/Db/Task.php index 3ac4facf97eab..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 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 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 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/TemplateLayout.php b/lib/private/TemplateLayout.php index bce2422be0abc..6ad88381c320b 100644 --- a/lib/private/TemplateLayout.php +++ b/lib/private/TemplateLayout.php @@ -43,9 +43,9 @@ use OCP\Util; class TemplateLayout { - private static string $versionHash = ''; + private string $versionHash = ''; /** @var string[] */ - private static array $cacheBusterCache = []; + private array $cacheBusterCache = []; public ?CSSResourceLocator $cssLocator = null; public ?JSResourceLocator $jsLocator = null; @@ -211,13 +211,13 @@ public function getPageTemplate(string $renderAs, string $appId): ITemplate { $page->assign('enabledThemes', $themesService?->getEnabledThemes() ?? []); if ($this->config->getSystemValueBool('installed', false)) { - if (empty(self::$versionHash)) { + if (empty($this->versionHash)) { $v = $this->appManager->getAppInstalledVersions(true); $v['core'] = implode('.', $this->serverVersion->getVersion()); - self::$versionHash = substr(md5(implode(',', $v)), 0, 8); + $this->versionHash = substr(md5(implode(',', $v)), 0, 8); } } else { - self::$versionHash = md5('not installed'); + $this->versionHash = md5('not installed'); } // Add the js files @@ -247,7 +247,7 @@ public function getPageTemplate(string $renderAs, string $appId): ITemplate { if (Server::get(ContentSecurityPolicyNonceManager::class)->browserSupportsCspV3()) { $page->assign('inline_ocjs', $config); } else { - $page->append('jsfiles', Server::get(IURLGenerator::class)->linkToRoute('core.OCJS.getConfig', ['v' => self::$versionHash])); + $page->append('jsfiles', Server::get(IURLGenerator::class)->linkToRoute('core.OCJS.getConfig', ['v' => $this->versionHash])); } } foreach ($jsFiles as $info) { @@ -280,7 +280,7 @@ public function getPageTemplate(string $renderAs, string $appId): ITemplate { $page->assign('cssfiles', []); $page->assign('printcssfiles', []); - $this->initialState->provideInitialState('core', 'versionHash', self::$versionHash); + $this->initialState->provideInitialState('core', 'versionHash', $this->versionHash); foreach ($cssFiles as $info) { $web = $info[1]; $file = $info[2]; @@ -320,7 +320,7 @@ protected function getVersionHashSuffix(string $path = '', string $file = ''): s if ($this->config->getSystemValueBool('installed', false) === false) { // if not installed just return the version hash - return '?v=' . self::$versionHash; + return '?v=' . $this->versionHash; } $hash = false; @@ -334,7 +334,7 @@ protected function getVersionHashSuffix(string $path = '', string $file = ''): s } // As a last resort we use the server version hash if ($hash === false) { - $hash = self::$versionHash; + $hash = $this->versionHash; } // The theming app is force-enabled thus the cache buster is always available @@ -344,7 +344,7 @@ protected function getVersionHashSuffix(string $path = '', string $file = ''): s } private function getVersionHashByPath(string $path): string|false { - if (array_key_exists($path, self::$cacheBusterCache) === false) { + if (array_key_exists($path, $this->cacheBusterCache) === false) { // Not yet cached, so lets find the cache buster string $appId = $this->getAppNamefromPath($path); if ($appId === false) { @@ -354,20 +354,20 @@ private function getVersionHashByPath(string $path): string|false { if ($appId === 'core') { // core is not a real app but the server itself - $hash = self::$versionHash; + $hash = $this->versionHash; } else { $appVersion = $this->appManager->getAppVersion($appId); // For shipped apps the app version is not a single source of truth, we rather also need to consider the Nextcloud version if ($this->appManager->isShipped($appId)) { - $appVersion .= '-' . self::$versionHash; + $appVersion .= '-' . $this->versionHash; } $hash = substr(md5($appVersion), 0, 8); } - self::$cacheBusterCache[$path] = $hash; + $this->cacheBusterCache[$path] = $hash; } - return self::$cacheBusterCache[$path]; + return $this->cacheBusterCache[$path]; } private function findStylesheetFiles(array $styles): array { diff --git a/lib/private/TextProcessing/Db/Task.php b/lib/private/TextProcessing/Db/Task.php index d4ebc19e74a7e..d6144a69074d3 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 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 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..1aedcc891d2ad 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 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..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 static 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 static 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() { @@ -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))); diff --git a/lib/public/Util.php b/lib/public/Util.php index 0ecfc95075b4f..903582db70e82 100644 --- a/lib/public/Util.php +++ b/lib/public/Util.php @@ -27,6 +27,7 @@ class Util { private static array $scriptsInit = []; private static array $scripts = []; private static array $scriptDeps = []; + private static ?bool $needUpgradeCache = null; /** * get the current installed version of Nextcloud @@ -575,8 +576,6 @@ public static function isDefaultExpireDateEnforced() { return \OC_Util::isDefaultExpireDateEnforced(); } - protected static $needUpgradeCache = null; - /** * Checks whether the current version needs upgrade. * @@ -584,7 +583,7 @@ public static function isDefaultExpireDateEnforced() { * @since 7.0.0 */ public static function needUpgrade() { - if (!isset(self::$needUpgradeCache)) { + if (self::$needUpgradeCache === null) { self::$needUpgradeCache = \OC_Util::needUpgrade(\OCP\Server::get(\OC\SystemConfig::class)); } return self::$needUpgradeCache; diff --git a/psalm.xml b/psalm.xml index 9b029ce31d497..adfaefffdd9fe 100644 --- a/psalm.xml +++ b/psalm.xml @@ -18,6 +18,7 @@ +