From dc1a89012656540bf31c757350953db32845c563 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maur=C3=ADcio=20Meneghini=20Fauth?= Date: Wed, 7 Jan 2026 22:37:05 -0300 Subject: [PATCH] Extract function to load services from services file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extracts to ContainerBuilder::loadServices(), removes service alias support and add unit tests. Signed-off-by: MaurĂ­cio Meneghini Fauth --- app/services_loader.php | 38 ++-------- phpstan-baseline.neon | 72 ++----------------- psalm-baseline.xml | 27 ++----- src/Container/ContainerBuilder.php | 23 ++++++ tests/unit/Container/ContainerBuilderTest.php | 59 +++++++++++++++ 5 files changed, 100 insertions(+), 119 deletions(-) diff --git a/app/services_loader.php b/app/services_loader.php index 8e122597ae..ed6e670f95 100644 --- a/app/services_loader.php +++ b/app/services_loader.php @@ -2,41 +2,17 @@ declare(strict_types=1); -namespace Symfony\Component\DependencyInjection\Loader\Configurator; - -use Symfony\Component\DependencyInjection\Reference; - -use function is_string; +use PhpMyAdmin\Container\ContainerBuilder; +use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; return static function (ContainerConfigurator $configurator): void { $services = $configurator->services(); - /** @param array, factory?: callable}> $servicesFile */ - $loadServices = static function (array $servicesFile, ServicesConfigurator $services): void { - foreach ($servicesFile as $serviceName => $service) { - if (is_string($service)) { - $services->alias($serviceName, $service); - continue; - } - - $theService = $services->set($serviceName, $service['class']); - if (isset($service['factory'])) { - $theService->factory($service['factory']); - } - - if (! isset($service['arguments'])) { - continue; - } - - foreach ($service['arguments'] as &$argumentName) { - $argumentName = new Reference($argumentName); - } - - $theService->args($service['arguments']); - } - }; + /** @var array, factory?: callable}> $servicesFile */ $servicesFile = include ROOT_PATH . 'app/services.php'; - $loadServices($servicesFile, $services); + ContainerBuilder::loadServices($servicesFile, $services); + + /** @var array, factory?: callable}> $servicesFile */ $servicesFile = include ROOT_PATH . 'app/services_controllers.php'; - $loadServices($servicesFile, $services); + ContainerBuilder::loadServices($servicesFile, $services); }; diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 0956f201ff..76724f20a6 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -6,72 +6,6 @@ parameters: count: 11 path: app/constants.php - - - message: '#^Argument of an invalid type mixed supplied for foreach, only iterables are supported\.$#' - identifier: foreach.nonIterable - count: 1 - path: app/services_loader.php - - - - message: '#^Cannot access offset ''arguments'' on mixed\.$#' - identifier: offsetAccess.nonOffsetAccessible - count: 1 - path: app/services_loader.php - - - - message: '#^Cannot access offset ''class'' on mixed\.$#' - identifier: offsetAccess.nonOffsetAccessible - count: 1 - path: app/services_loader.php - - - - message: '#^Cannot access offset ''factory'' on mixed\.$#' - identifier: offsetAccess.nonOffsetAccessible - count: 1 - path: app/services_loader.php - - - - message: '#^Parameter \#1 \$arguments of method Symfony\\Component\\DependencyInjection\\Loader\\Configurator\\ServiceConfigurator\:\:args\(\) expects array, mixed given\.$#' - identifier: argument.type - count: 1 - path: app/services_loader.php - - - - message: '#^Parameter \#1 \$factory of method Symfony\\Component\\DependencyInjection\\Loader\\Configurator\\ServiceConfigurator\:\:factory\(\) expects array\|Closure\|string\|Symfony\\Component\\DependencyInjection\\Loader\\Configurator\\ReferenceConfigurator\|Symfony\\Component\\ExpressionLanguage\\Expression, mixed given\.$#' - identifier: argument.type - count: 1 - path: app/services_loader.php - - - - message: '#^Parameter \#1 \$id of class Symfony\\Component\\DependencyInjection\\Reference constructor expects string, mixed given\.$#' - identifier: argument.type - count: 1 - path: app/services_loader.php - - - - message: '#^Parameter \#1 \$id of method Symfony\\Component\\DependencyInjection\\Loader\\Configurator\\ServicesConfigurator\:\:alias\(\) expects string, \(int\|string\) given\.$#' - identifier: argument.type - count: 1 - path: app/services_loader.php - - - - message: '#^Parameter \#1 \$id of method Symfony\\Component\\DependencyInjection\\Loader\\Configurator\\ServicesConfigurator\:\:set\(\) expects string\|null, \(int\|string\) given\.$#' - identifier: argument.type - count: 1 - path: app/services_loader.php - - - - message: '#^Parameter \#1 \$servicesFile of closure expects array, mixed given\.$#' - identifier: argument.type - count: 2 - path: app/services_loader.php - - - - message: '#^Parameter \#2 \$class of method Symfony\\Component\\DependencyInjection\\Loader\\Configurator\\ServicesConfigurator\:\:set\(\) expects string\|null, mixed given\.$#' - identifier: argument.type - count: 1 - path: app/services_loader.php - - message: '#^Access to constant FORMAT_HTTP on an unknown class OpenID_Message\.$#' identifier: class.notFound @@ -1590,6 +1524,12 @@ parameters: count: 1 path: src/Console/History.php + - + message: '#^Parameter \#1 \$factory of method Symfony\\Component\\DependencyInjection\\Loader\\Configurator\\ServiceConfigurator\:\:factory\(\) expects array\|Closure\|string\|Symfony\\Component\\DependencyInjection\\Loader\\Configurator\\ReferenceConfigurator\|Symfony\\Component\\ExpressionLanguage\\Expression, callable\(\)\: mixed given\.$#' + identifier: argument.type + count: 1 + path: src/Container/ContainerBuilder.php + - message: '#^Binary operation "\.\=" between mixed and '' \-\> '' results in an error\.$#' identifier: assignOp.invalid diff --git a/psalm-baseline.xml b/psalm-baseline.xml index b862d7d5ce..4ce43a0919 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -1,27 +1,5 @@ - - - - - - - - - - - - - - - - - - - - - - @@ -676,6 +654,11 @@ + + + + + diff --git a/src/Container/ContainerBuilder.php b/src/Container/ContainerBuilder.php index 290bc7a8c4..9d60135ee9 100644 --- a/src/Container/ContainerBuilder.php +++ b/src/Container/ContainerBuilder.php @@ -7,7 +7,9 @@ namespace PhpMyAdmin\Container; use Psr\Container\ContainerInterface; use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\ContainerBuilder as SymfonyContainerBuilder; +use Symfony\Component\DependencyInjection\Loader\Configurator\ServicesConfigurator; use Symfony\Component\DependencyInjection\Loader\PhpFileLoader; +use Symfony\Component\DependencyInjection\Reference; use const ROOT_PATH; @@ -34,4 +36,25 @@ final class ContainerBuilder return $container; } + + /** @param array, factory?: callable}> $services */ + public static function loadServices(array $services, ServicesConfigurator $servicesConfigurator): void + { + foreach ($services as $serviceName => $service) { + $serviceConfigurator = $servicesConfigurator->set($serviceName, $service['class']); + if (isset($service['factory'])) { + $serviceConfigurator->factory($service['factory']); + } + + if (! isset($service['arguments'])) { + continue; + } + + foreach ($service['arguments'] as &$argument) { + $argument = new Reference($argument); + } + + $serviceConfigurator->args($service['arguments']); + } + } } diff --git a/tests/unit/Container/ContainerBuilderTest.php b/tests/unit/Container/ContainerBuilderTest.php index c4cd64a3e7..84ea079d37 100644 --- a/tests/unit/Container/ContainerBuilderTest.php +++ b/tests/unit/Container/ContainerBuilderTest.php @@ -4,12 +4,19 @@ declare(strict_types=1); namespace PhpMyAdmin\Tests\Container; +use PhpMyAdmin\Config; use PhpMyAdmin\Container\ContainerBuilder; use PhpMyAdmin\Current; +use PhpMyAdmin\Database\Events; use PhpMyAdmin\Dbal\DatabaseInterface; +use PhpMyAdmin\FlashMessenger; use PhpMyAdmin\Tests\AbstractTestCase; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\DataProvider; +use Symfony\Component\DependencyInjection\ContainerBuilder as SymfonyContainerBuilder; +use Symfony\Component\DependencyInjection\Loader\Configurator\ServicesConfigurator; +use Symfony\Component\DependencyInjection\Loader\PhpFileLoader; +use Symfony\Component\DependencyInjection\Reference; use function array_keys; use function array_map; @@ -52,4 +59,56 @@ final class ContainerBuilderTest extends AbstractTestCase array_merge(array_keys($services), array_keys($controllerServices)), ); } + + public function testLoadServices(): void + { + $container = new SymfonyContainerBuilder(); + $loader = self::createStub(PhpFileLoader::class); + $instanceof = []; + $servicesConfigurator = new ServicesConfigurator($container, $loader, $instanceof); + + $services = [ + Config::class => ['class' => Config::class, 'factory' => [Config::class, 'getInstance']], + DatabaseInterface::class => [ + 'class' => DatabaseInterface::class, + 'factory' => [DatabaseInterface::class, 'getInstance'], + 'arguments' => [Config::class], + ], + Events::class => ['class' => Events::class, 'arguments' => [DatabaseInterface::class, Config::class]], + FlashMessenger::class => ['class' => FlashMessenger::class], + ]; + + ContainerBuilder::loadServices($services, $servicesConfigurator); + + $definitions = $container->getDefinitions(); + + self::assertArrayHasKey(Config::class, $definitions); + self::assertSame(Config::class, $definitions[Config::class]->getClass()); + self::assertSame([Config::class, 'getInstance'], $definitions[Config::class]->getFactory()); + self::assertSame([], $definitions[Config::class]->getArguments()); + + self::assertArrayHasKey(DatabaseInterface::class, $definitions); + self::assertSame(DatabaseInterface::class, $definitions[DatabaseInterface::class]->getClass()); + self::assertSame( + [DatabaseInterface::class, 'getInstance'], + $definitions[DatabaseInterface::class]->getFactory(), + ); + self::assertEquals( + [new Reference(Config::class)], + $definitions[DatabaseInterface::class]->getArguments(), + ); + + self::assertArrayHasKey(Events::class, $definitions); + self::assertSame(Events::class, $definitions[Events::class]->getClass()); + self::assertNull($definitions[Events::class]->getFactory()); + self::assertEquals( + [new Reference(DatabaseInterface::class), new Reference(Config::class)], + $definitions[Events::class]->getArguments(), + ); + + self::assertArrayHasKey(FlashMessenger::class, $definitions); + self::assertSame(FlashMessenger::class, $definitions[FlashMessenger::class]->getClass()); + self::assertNull($definitions[FlashMessenger::class]->getFactory()); + self::assertSame([], $definitions[FlashMessenger::class]->getArguments()); + } }