From 9dc1d6372fb16261e2b6724af04f79fe57c824e9 Mon Sep 17 00:00:00 2001 From: provokateurin Date: Mon, 16 Feb 2026 08:41:03 +0100 Subject: [PATCH 1/4] fix(IContainer): Fix parameter and return types Signed-off-by: provokateurin --- build/rector-strict.php | 1 + .../DependencyInjection/DIContainer.php | 2 +- .../AppFramework/Utility/SimpleContainer.php | 14 +++----- lib/private/ServerContainer.php | 2 +- lib/public/IContainer.php | 35 +++++++------------ psalm-strict.xml | 1 + .../Collaborators/SearchTest.php | 16 ++++----- 7 files changed, 29 insertions(+), 42 deletions(-) diff --git a/build/rector-strict.php b/build/rector-strict.php index 26dbea397dbc0..529eace3b6743 100644 --- a/build/rector-strict.php +++ b/build/rector-strict.php @@ -11,6 +11,7 @@ ->withPaths([ $nextcloudDir . '/build/rector-strict.php', $nextcloudDir . '/core/BackgroundJobs/ExpirePreviewsJob.php', + $nextcloudDir . '/lib/public/IContainer.php', ]) ->withPreparedSets( deadCode: true, diff --git a/lib/private/AppFramework/DependencyInjection/DIContainer.php b/lib/private/AppFramework/DependencyInjection/DIContainer.php index 258c88f56f87b..c316bdab6ac8f 100644 --- a/lib/private/AppFramework/DependencyInjection/DIContainer.php +++ b/lib/private/AppFramework/DependencyInjection/DIContainer.php @@ -326,7 +326,7 @@ public function has($id): bool { * @inheritDoc * @param list $chain */ - public function query(string $name, bool $autoload = true, array $chain = []) { + public function query(string $name, bool $autoload = true, array $chain = []): mixed { if ($name === 'AppName' || $name === 'appName') { return $this->appName; } diff --git a/lib/private/AppFramework/Utility/SimpleContainer.php b/lib/private/AppFramework/Utility/SimpleContainer.php index 7aade20c65891..429b7d617ed8f 100644 --- a/lib/private/AppFramework/Utility/SimpleContainer.php +++ b/lib/private/AppFramework/Utility/SimpleContainer.php @@ -120,7 +120,7 @@ private function buildClassConstructorParameters(\ReflectionMethod $constructor, * @inheritDoc * @param list $chain */ - public function resolve($name, array $chain = []) { + public function resolve(string $name, array $chain = []): mixed { $baseMsg = 'Could not resolve ' . $name . '!'; try { $class = new ReflectionClass($name); @@ -140,7 +140,7 @@ public function resolve($name, array $chain = []) { * @inheritDoc * @param list $chain */ - public function query(string $name, bool $autoload = true, array $chain = []) { + public function query(string $name, bool $autoload = true, array $chain = []): mixed { $name = $this->sanitizeName($name); if (isset($this->container[$name])) { return $this->container[$name]; @@ -161,15 +161,11 @@ public function query(string $name, bool $autoload = true, array $chain = []) { throw new QueryNotFoundException('Could not resolve ' . $name . '!'); } - /** - * @param string $name - * @param mixed $value - */ - public function registerParameter($name, $value) { + public function registerParameter(string $name, mixed $value): void { $this[$name] = $value; } - public function registerService($name, Closure $closure, $shared = true) { + public function registerService(string $name, Closure $closure, bool $shared = true): void { $wrapped = function () use ($closure) { return $closure($this); }; @@ -191,7 +187,7 @@ public function registerService($name, Closure $closure, $shared = true) { * @param string $alias the alias that should be registered * @param string $target the target that should be resolved instead */ - public function registerAlias($alias, $target): void { + public function registerAlias(string $alias, string $target): void { $this->registerService($alias, function (ContainerInterface $container) use ($target): mixed { return $container->get($target); }, false); diff --git a/lib/private/ServerContainer.php b/lib/private/ServerContainer.php index a63615d21bbca..c06c2c46acf0b 100644 --- a/lib/private/ServerContainer.php +++ b/lib/private/ServerContainer.php @@ -119,7 +119,7 @@ public function has($id, bool $noRecursion = false): bool { * @throws QueryException * @deprecated 20.0.0 use \Psr\Container\ContainerInterface::get */ - public function query(string $name, bool $autoload = true, array $chain = []) { + public function query(string $name, bool $autoload = true, array $chain = []): mixed { $name = $this->sanitizeName($name); if (str_starts_with($name, 'OCA\\')) { diff --git a/lib/public/IContainer.php b/lib/public/IContainer.php index 9db3069f87f1d..22d867c1acc02 100644 --- a/lib/public/IContainer.php +++ b/lib/public/IContainer.php @@ -1,5 +1,7 @@ $name - * @return \stdClass - * @psalm-return ($name is class-string ? T : mixed) + * @param class-string|string $name + * @return ($name is class-string ? T : mixed) * @since 8.2.0 * @deprecated 20.0.0 use \Psr\Container\ContainerInterface::get * @throws ContainerExceptionInterface if the class could not be found or instantiated */ - public function resolve($name); + public function resolve(string $name): mixed; /** * Look up a service for a given name in the container. * * @template T - * - * @param string $name - * @psalm-param string|class-string $name + * @param class-string|string $name * @param bool $autoload Should we try to autoload the service. If we are trying to resolve built in types this makes no sense for example - * @return mixed - * @psalm-return ($name is class-string ? T : mixed) + * @return ($name is class-string ? T : mixed) * @throws ContainerExceptionInterface if the query could not be resolved * @throws NotFoundExceptionInterface if the name could not be found within the container * @since 6.0.0 * @deprecated 20.0.0 use \Psr\Container\ContainerInterface::get */ - public function query(string $name, bool $autoload = true); + public function query(string $name, bool $autoload = true): mixed; /** * A value is stored in the container with it's corresponding name * - * @param string $name - * @param mixed $value - * @return void * @since 6.0.0 * @deprecated 20.0.0 use \OCP\AppFramework\Bootstrap\IRegistrationContext::registerParameter */ - public function registerParameter($name, $value); + public function registerParameter(string $name, mixed $value): void; /** * A service is registered in the container where a closure is passed in which will actually @@ -75,14 +67,11 @@ public function registerParameter($name, $value); * memory and be reused on subsequent calls. * In case the parameter is false the service will be recreated on every call. * - * @param string $name - * @param \Closure(SimpleContainer): mixed $closure - * @param bool $shared - * @return void + * @param \Closure(IContainer): mixed $closure * @since 6.0.0 * @deprecated 20.0.0 use \OCP\AppFramework\Bootstrap\IRegistrationContext::registerService */ - public function registerService($name, Closure $closure, $shared = true); + public function registerService(string $name, Closure $closure, bool $shared = true): void; /** * Shortcut for returning a service from a service under a different key, @@ -93,5 +82,5 @@ public function registerService($name, Closure $closure, $shared = true); * @since 8.2.0 * @deprecated 20.0.0 use \OCP\AppFramework\Bootstrap\IRegistrationContext::registerServiceAlias */ - public function registerAlias($alias, $target); + public function registerAlias(string $alias, string $target): void; } diff --git a/psalm-strict.xml b/psalm-strict.xml index 6a879070ee82a..900470bcbab17 100644 --- a/psalm-strict.xml +++ b/psalm-strict.xml @@ -17,6 +17,7 @@ > + diff --git a/tests/lib/Collaboration/Collaborators/SearchTest.php b/tests/lib/Collaboration/Collaborators/SearchTest.php index ade995ea5262e..7cff155a0c0bf 100644 --- a/tests/lib/Collaboration/Collaborators/SearchTest.php +++ b/tests/lib/Collaboration/Collaborators/SearchTest.php @@ -91,22 +91,22 @@ public function testSearch( ->willReturnCallback(function ($class) use ($searchResult, $userPlugin, $groupPlugin, $remotePlugin, $mailPlugin) { if ($class === SearchResult::class) { return $searchResult; - } elseif ($class === $userPlugin) { + } elseif ($class === 'user') { return $userPlugin; - } elseif ($class === $groupPlugin) { + } elseif ($class === 'group') { return $groupPlugin; - } elseif ($class === $remotePlugin) { + } elseif ($class === 'remote') { return $remotePlugin; - } elseif ($class === $mailPlugin) { + } elseif ($class === 'mail') { return $mailPlugin; } return null; }); - $this->search->registerPlugin(['shareType' => 'SHARE_TYPE_USER', 'class' => $userPlugin]); - $this->search->registerPlugin(['shareType' => 'SHARE_TYPE_GROUP', 'class' => $groupPlugin]); - $this->search->registerPlugin(['shareType' => 'SHARE_TYPE_REMOTE', 'class' => $remotePlugin]); - $this->search->registerPlugin(['shareType' => 'SHARE_TYPE_EMAIL', 'class' => $mailPlugin]); + $this->search->registerPlugin(['shareType' => 'SHARE_TYPE_USER', 'class' => 'user']); + $this->search->registerPlugin(['shareType' => 'SHARE_TYPE_GROUP', 'class' => 'group']); + $this->search->registerPlugin(['shareType' => 'SHARE_TYPE_REMOTE', 'class' => 'remote']); + $this->search->registerPlugin(['shareType' => 'SHARE_TYPE_EMAIL', 'class' => 'mail']); [$results, $moreResults] = $this->search->search($searchTerm, $shareTypes, false, $perPage, $perPage * ($page - 1)); From 935c2416b515aeebeba31c96bef203c1221743e0 Mon Sep 17 00:00:00 2001 From: provokateurin Date: Mon, 16 Feb 2026 09:13:54 +0100 Subject: [PATCH 2/4] fix(IContainer): Override get method with better type annotations Signed-off-by: provokateurin --- lib/public/IContainer.php | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/lib/public/IContainer.php b/lib/public/IContainer.php index 22d867c1acc02..71f310329061e 100644 --- a/lib/public/IContainer.php +++ b/lib/public/IContainer.php @@ -25,6 +25,20 @@ * @deprecated 20.0.0 use \Psr\Container\ContainerInterface */ interface IContainer extends ContainerInterface { + /** + * Finds an entry of the container by its identifier and returns it. + * + * @template T + * @param class-string|string $id Identifier of the entry to look for. + * + * @throws NotFoundExceptionInterface No entry was found for **this** identifier. + * @throws ContainerExceptionInterface Error while retrieving the entry. + * + * @return ($id is class-string ? T : mixed) Entry. + * @since 34.0.0 + */ + public function get(string $id); + /** * @template T * @@ -33,7 +47,7 @@ interface IContainer extends ContainerInterface { * @param class-string|string $name * @return ($name is class-string ? T : mixed) * @since 8.2.0 - * @deprecated 20.0.0 use \Psr\Container\ContainerInterface::get + * @deprecated 20.0.0 use {@see self::get()} * @throws ContainerExceptionInterface if the class could not be found or instantiated */ public function resolve(string $name): mixed; @@ -48,7 +62,7 @@ public function resolve(string $name): mixed; * @throws ContainerExceptionInterface if the query could not be resolved * @throws NotFoundExceptionInterface if the name could not be found within the container * @since 6.0.0 - * @deprecated 20.0.0 use \Psr\Container\ContainerInterface::get + * @deprecated 20.0.0 use {@see self::get()} */ public function query(string $name, bool $autoload = true): mixed; From 931d15e476853d1dfae5596cdbacda23f19486e1 Mon Sep 17 00:00:00 2001 From: provokateurin Date: Mon, 16 Feb 2026 08:42:20 +0100 Subject: [PATCH 3/4] feat(IContainer): Undeprecate class Signed-off-by: provokateurin --- lib/public/IContainer.php | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/public/IContainer.php b/lib/public/IContainer.php index 71f310329061e..9f8a38ca2fdfa 100644 --- a/lib/public/IContainer.php +++ b/lib/public/IContainer.php @@ -22,7 +22,6 @@ * IContainer is the basic interface to be used for any internal dependency injection mechanism * * @since 6.0.0 - * @deprecated 20.0.0 use \Psr\Container\ContainerInterface */ interface IContainer extends ContainerInterface { /** From d92c2de7415db4b1cfc40c4f72807eba713c6f32 Mon Sep 17 00:00:00 2001 From: provokateurin Date: Mon, 16 Feb 2026 09:08:39 +0100 Subject: [PATCH 4/4] fix(IRegistrationContext): Use IContainer in registerService factory Signed-off-by: provokateurin --- lib/public/AppFramework/Bootstrap/IRegistrationContext.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/public/AppFramework/Bootstrap/IRegistrationContext.php b/lib/public/AppFramework/Bootstrap/IRegistrationContext.php index 5a9785297c2a5..85ba659111145 100644 --- a/lib/public/AppFramework/Bootstrap/IRegistrationContext.php +++ b/lib/public/AppFramework/Bootstrap/IRegistrationContext.php @@ -9,7 +9,6 @@ namespace OCP\AppFramework\Bootstrap; -use OC\AppFramework\Utility\SimpleContainer; use OCP\AppFramework\IAppContainer; use OCP\Authentication\TwoFactorAuth\IProvider; use OCP\Calendar\ICalendarProvider; @@ -69,7 +68,7 @@ public function registerDashboardWidget(string $widgetClass): void; * * @param string $name * @param callable $factory - * @psalm-param callable(SimpleContainer): mixed $factory + * @psalm-param callable(IContainer): mixed $factory * @param bool $shared If set to true the factory result will be cached otherwise every query will call the factory again * * @return void