From c1a3ef06e6ad708957dbb745ab4994738c0481ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=B4me=20Chilliet?= Date: Thu, 17 Sep 2026 18:09:56 +0200 Subject: [PATCH] chore: Remove deprecated interface ArrayAccess on the container MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Côme Chilliet --- build/psalm-baseline.xml | 6 -- lib/private/AppFramework/App.php | 12 ++-- .../AppFramework/Utility/SimpleContainer.php | 35 +++--------- lib/private/Server.php | 4 +- lib/private/ServerContainer.php | 2 +- tests/lib/AppFramework/AppTest.php | 26 ++++----- .../DependencyInjection/DIContainerTest.php | 56 +++++++++---------- tests/lib/TestCase.php | 19 ++++--- 8 files changed, 67 insertions(+), 93 deletions(-) diff --git a/build/psalm-baseline.xml b/build/psalm-baseline.xml index 9b2187a267953..8d2bedba96725 100644 --- a/build/psalm-baseline.xml +++ b/build/psalm-baseline.xml @@ -3222,9 +3222,6 @@ - - - getCode()]]> @@ -4063,9 +4060,6 @@ - - - diff --git a/lib/private/AppFramework/App.php b/lib/private/AppFramework/App.php index 5160fd61c83d7..1c6c30f23dc26 100644 --- a/lib/private/AppFramework/App.php +++ b/lib/private/AppFramework/App.php @@ -79,7 +79,7 @@ public static function main( $profiler->setEnabled($profiler->isEnabled() && !is_null($urlParams) && isset($urlParams['_route']) && !str_starts_with($urlParams['_route'], 'profiler.')); if ($profiler->isEnabled()) { Server::get(IEventLogger::class)->activate(); - $profiler->add(new RoutingDataCollector($container['appName'], $controllerName, $methodName)); + $profiler->add(new RoutingDataCollector($container->get('appName'), $controllerName, $methodName)); } $eventLogger->start('app:controller:params', 'Gather controller parameters'); @@ -88,12 +88,12 @@ public static function main( /** @var Request $request */ $request = $container->get(IRequest::class); $request->setUrlParameters($urlParams); - } elseif (isset($container['urlParams']) && !is_null($container['urlParams'])) { + } elseif ($container->has('urlParams') && !is_null($container->get('urlParams'))) { /** @var Request $request */ $request = $container->get(IRequest::class); - $request->setUrlParameters($container['urlParams']); + $request->setUrlParameters($container->get('urlParams')); } - $appName = $container['appName']; + $appName = $container->get('appName'); $eventLogger->end('app:controller:params'); @@ -139,7 +139,7 @@ public static function main( $eventLogger->end('app:controller:run'); - $io = $container[IOutput::class]; + $io = $container->get(IOutput::class); if ($profiler->isEnabled()) { $eventLogger->end('runtime'); @@ -169,7 +169,7 @@ public static function main( $value['value'], $expireDate, $container->get('webRoot'), - null, + '', $container->getServer()->get(IRequest::class)->getServerProtocol() === 'https', true, $sameSite diff --git a/lib/private/AppFramework/Utility/SimpleContainer.php b/lib/private/AppFramework/Utility/SimpleContainer.php index 6246a56ac209b..68d15ef13a708 100644 --- a/lib/private/AppFramework/Utility/SimpleContainer.php +++ b/lib/private/AppFramework/Utility/SimpleContainer.php @@ -8,7 +8,6 @@ namespace OC\AppFramework\Utility; -use ArrayAccess; use Closure; use OCP\AppFramework\QueryException; use OCP\IContainer; @@ -26,7 +25,7 @@ /** * SimpleContainer is a simple implementation of a container on basis of Pimple */ -class SimpleContainer implements ArrayAccess, ContainerInterface, IContainer { +class SimpleContainer implements ContainerInterface, IContainer { /** @psalm-suppress ImpureStaticProperty A static property is the only way to pass the information from config to autoload */ public static bool $useLazyObjects = false; @@ -254,36 +253,16 @@ protected function sanitizeName($name) { } /** - * @deprecated 20.0.0 use \Psr\Container\ContainerInterface::has + * @internal Used by tests */ - #[\Override] - public function offsetExists($id): bool { - return $this->container->offsetExists($id); - } - - /** - * @deprecated 20.0.0 use \Psr\Container\ContainerInterface::get - * @return mixed - */ - #[\Override] - #[\ReturnTypeWillChange] - public function offsetGet($id) { - return $this->container->offsetGet($id); + public function removeFromInternalContainer(string $service): void { + unset($this->container[$service]); } /** - * @deprecated 20.0.0 use \OCP\IContainer::registerService + * @internal Used by server container on app containers */ - #[\Override] - public function offsetSet($offset, $value): void { - $this->container->offsetSet($offset, $value); - } - - /** - * @deprecated 20.0.0 - */ - #[\Override] - public function offsetUnset($offset): void { - $this->container->offsetUnset($offset); + public function setInInternalContainer(string $service, mixed $value): void { + $this->container[$service] = $value; } } diff --git a/lib/private/Server.php b/lib/private/Server.php index f54a9568e55cf..ad3692f1da3e3 100644 --- a/lib/private/Server.php +++ b/lib/private/Server.php @@ -781,8 +781,8 @@ public function __construct( ); }); $this->registerService(Request::class, function (ContainerInterface $c) { - if (isset($this['urlParams'])) { - $urlParams = $this['urlParams']; + if ($this->has('urlParams')) { + $urlParams = $this->get('urlParams'); } else { $urlParams = []; } diff --git a/lib/private/ServerContainer.php b/lib/private/ServerContainer.php index 484f2647d2a65..0261e2996f4cd 100644 --- a/lib/private/ServerContainer.php +++ b/lib/private/ServerContainer.php @@ -89,7 +89,7 @@ protected function getAppContainer(string $sensitiveNamespace): DIContainer { /* The application constructor will register the container, see App::__construct */ $app = new $applicationClassName(); if (isset($this->appContainers[$namespace])) { - $this->appContainers[$namespace]->offsetSet($applicationClassName, $app); + $this->appContainers[$namespace]->setInInternalContainer($applicationClassName, $app); /** @psalm-suppress NoValue false-positive (see comment above) */ return $this->appContainers[$namespace]; } diff --git a/tests/lib/AppFramework/AppTest.php b/tests/lib/AppFramework/AppTest.php index 334eeefdab6c2..149c969e8d3fd 100644 --- a/tests/lib/AppFramework/AppTest.php +++ b/tests/lib/AppFramework/AppTest.php @@ -54,10 +54,10 @@ protected function setUp(): void { $this->controllerName = 'Controller'; $this->controllerMethod = 'method'; - $this->container[$this->controllerName] = $this->controller; - $this->container[Dispatcher::class] = $this->dispatcher; - $this->container[IOutput::class] = $this->io; - $this->container['urlParams'] = ['_route' => 'not-profiler']; + $this->container->setInInternalContainer($this->controllerName, $this->controller); + $this->container->setInInternalContainer(Dispatcher::class, $this->dispatcher); + $this->container->setInInternalContainer(IOutput::class, $this->io); + $this->container->registerParameter('urlParams', ['_route' => 'not-profiler']); $this->appPath = __DIR__ . '/../../../apps/namespacetestapp'; $infoXmlPath = $this->appPath . '/appinfo/info.xml'; @@ -159,9 +159,9 @@ public function testCallbackIsCalled(): void { } public function testCoreApp(): void { - $this->container['appName'] = 'core'; - $this->container['OC\Core\Controller\Foo'] = $this->controller; - $this->container['urlParams'] = ['_route' => 'not-profiler']; + self::invokePrivate($this->container, 'appName', ['core']); + $this->container->setInInternalContainer('OC\Core\Controller\Foo', $this->controller); + $this->container->registerParameter('urlParams', ['_route' => 'not-profiler']); $return = ['HTTP/2.0 200 OK', [], [], null, new Response()]; $this->dispatcher->expects($this->once()) @@ -177,9 +177,9 @@ public function testCoreApp(): void { } public function testSettingsApp(): void { - $this->container['appName'] = 'settings'; - $this->container['OCA\Settings\Controller\Foo'] = $this->controller; - $this->container['urlParams'] = ['_route' => 'not-profiler']; + self::invokePrivate($this->container, 'appName', ['settings']); + $this->container->setInInternalContainer('OCA\Settings\Controller\Foo', $this->controller); + $this->container->registerParameter('urlParams', ['_route' => 'not-profiler']); $return = ['HTTP/2.0 200 OK', [], [], null, new Response()]; $this->dispatcher->expects($this->once()) @@ -195,9 +195,9 @@ public function testSettingsApp(): void { } public function testApp(): void { - $this->container['appName'] = 'bar'; - $this->container['OCA\Bar\Controller\Foo'] = $this->controller; - $this->container['urlParams'] = ['_route' => 'not-profiler']; + self::invokePrivate($this->container, 'appName', ['bar']); + $this->container->setInInternalContainer('OCA\Bar\Controller\Foo', $this->controller); + $this->container->registerParameter('urlParams', ['_route' => 'not-profiler']); $return = ['HTTP/2.0 200 OK', [], [], null, new Response()]; $this->dispatcher->expects($this->once()) diff --git a/tests/lib/AppFramework/DependencyInjection/DIContainerTest.php b/tests/lib/AppFramework/DependencyInjection/DIContainerTest.php index bd82677200460..8a9e2729b944d 100644 --- a/tests/lib/AppFramework/DependencyInjection/DIContainerTest.php +++ b/tests/lib/AppFramework/DependencyInjection/DIContainerTest.php @@ -36,30 +36,30 @@ protected function setUp(): void { } public function testProvidesRequest(): void { - $this->assertTrue(isset($this->container['Request'])); + $this->assertTrue($this->container->has('Request')); } public function testProvidesMiddlewareDispatcher(): void { - $this->assertTrue(isset($this->container['MiddlewareDispatcher'])); + $this->assertTrue($this->container->has('MiddlewareDispatcher')); } public function testProvidesAppName(): void { - $this->assertTrue(isset($this->container['AppName'])); - $this->assertTrue(isset($this->container['appName'])); + $this->assertTrue($this->container->has('AppName')); + $this->assertTrue($this->container->has('appName')); } public function testAppNameIsSetCorrectly(): void { - $this->assertEquals('name', $this->container['AppName']); - $this->assertEquals('name', $this->container['appName']); + $this->assertEquals('name', $this->container->get('AppName')); + $this->assertEquals('name', $this->container->get('appName')); } public function testMiddlewareDispatcherIncludesSecurityMiddleware(): void { - $this->container['Request'] = new Request( + $this->container->registerService('Request', fn () => new Request( ['method' => 'GET'], $this->createMock(IRequestId::class), $this->createMock(IConfig::class) - ); - $dispatcher = $this->container['MiddlewareDispatcher']; + )); + $dispatcher = $this->container->get('MiddlewareDispatcher'); $middlewares = $dispatcher->getMiddlewares(); $found = false; @@ -74,29 +74,29 @@ public function testMiddlewareDispatcherIncludesSecurityMiddleware(): void { public function testMiddlewareDispatcherIncludesBootstrapMiddlewares(): void { $coordinator = $this->createMock(Coordinator::class); - $this->container[Coordinator::class] = $coordinator; - $this->container['Request'] = $this->createMock(Request::class); + $this->container->registerService(Coordinator::class, fn () => $coordinator); + $this->container->registerService('Request', fn () => $this->createMock(Request::class)); $registrationContext = $this->createMock(RegistrationContext::class); $registrationContext->method('getMiddlewareRegistrations') ->willReturn([ - new MiddlewareRegistration($this->container['appName'], 'foo', false), + new MiddlewareRegistration($this->container->get('appName'), 'foo', false), new MiddlewareRegistration('otherapp', 'bar', false), ]); - $this->container['foo'] = new class extends Middleware { - }; - $this->container['bar'] = new class extends Middleware { - }; + $this->container->registerService('foo', fn () => new class extends Middleware { + }); + $this->container->registerService('bar', fn () => new class extends Middleware { + }); $coordinator->method('getRegistrationContext')->willReturn($registrationContext); - $dispatcher = $this->container['MiddlewareDispatcher']; + $dispatcher = $this->container->get('MiddlewareDispatcher'); $middlewares = $dispatcher->getMiddlewares(); self::assertNotEmpty($middlewares); foreach ($middlewares as $middleware) { - if ($middleware === $this->container['bar']) { + if ($middleware === $this->container->get('bar')) { $this->fail('Container must not register this middleware'); } - if ($middleware === $this->container['foo']) { + if ($middleware === $this->container->get('foo')) { // It is done return; } @@ -106,29 +106,29 @@ public function testMiddlewareDispatcherIncludesBootstrapMiddlewares(): void { public function testMiddlewareDispatcherIncludesGlobalBootstrapMiddlewares(): void { $coordinator = $this->createMock(Coordinator::class); - $this->container[Coordinator::class] = $coordinator; - $this->container['Request'] = $this->createMock(Request::class); + $this->container->registerService(Coordinator::class, fn () => $coordinator); + $this->container->registerService('Request', fn () => $this->createMock(Request::class)); $registrationContext = $this->createMock(RegistrationContext::class); $registrationContext->method('getMiddlewareRegistrations') ->willReturn([ new MiddlewareRegistration('otherapp', 'foo', true), new MiddlewareRegistration('otherapp', 'bar', false), ]); - $this->container['foo'] = new class extends Middleware { - }; - $this->container['bar'] = new class extends Middleware { - }; + $this->container->registerService('foo', fn () => new class extends Middleware { + }); + $this->container->registerService('bar', fn () => new class extends Middleware { + }); $coordinator->method('getRegistrationContext')->willReturn($registrationContext); - $dispatcher = $this->container['MiddlewareDispatcher']; + $dispatcher = $this->container->get('MiddlewareDispatcher'); $middlewares = $dispatcher->getMiddlewares(); self::assertNotEmpty($middlewares); foreach ($middlewares as $middleware) { - if ($middleware === $this->container['bar']) { + if ($middleware === $this->container->get('bar')) { $this->fail('Container must not register this middleware'); } - if ($middleware === $this->container['foo']) { + if ($middleware === $this->container->get('foo')) { // It is done return; } diff --git a/tests/lib/TestCase.php b/tests/lib/TestCase.php index f808947d4b75f..4a4ea3b728bc0 100644 --- a/tests/lib/TestCase.php +++ b/tests/lib/TestCase.php @@ -106,7 +106,8 @@ public function restoreService(string $name): bool { } else { // The service was not registered before the test override. // Remove the test registration so the container returns to its prior state. - unset($container[$name]); + /** @psalm-suppress InternalMethod */ + $container->removeFromInternalContainer($name); } unset($this->services[$name]); @@ -368,14 +369,14 @@ public static function tearDownAfterClass(): void { self::tearDownAfterClassCleanStrayLocks(); // Ensure we start with fresh instances of some classes to reduce side-effects between tests - /** @psalm-suppress DeprecatedMethod */ - unset(\OC::$server[Factory::class]); - /** @psalm-suppress DeprecatedMethod */ - unset(\OC::$server[AppFetcher::class]); - /** @psalm-suppress DeprecatedMethod */ - unset(\OC::$server[Installer::class]); - /** @psalm-suppress DeprecatedMethod */ - unset(\OC::$server[Updater::class]); + /** @psalm-suppress InternalMethod */ + \OC::$server->removeFromInternalContainer(Factory::class); + /** @psalm-suppress InternalMethod */ + \OC::$server->removeFromInternalContainer(AppFetcher::class); + /** @psalm-suppress InternalMethod */ + \OC::$server->removeFromInternalContainer(Installer::class); + /** @psalm-suppress InternalMethod */ + \OC::$server->removeFromInternalContainer(Updater::class); /** @var SetupManager $setupManager */ $setupManager = Server::get(SetupManager::class);