diff --git a/src/Symfony/Component/DependencyInjection/Attribute/AsTaggedItem.php b/src/Symfony/Component/DependencyInjection/Attribute/AsTaggedItem.php index 2e649bdeaaadd..6b1a94dd3dd35 100644 --- a/src/Symfony/Component/DependencyInjection/Attribute/AsTaggedItem.php +++ b/src/Symfony/Component/DependencyInjection/Attribute/AsTaggedItem.php @@ -20,8 +20,8 @@ class AsTaggedItem { /** - * @param string|null $index The property or method to use to index the item in the locator - * @param int|null $priority The priority of the item; the higher the number, the earlier the tagged service will be located in the locator + * @param string|null $index The property or method to use to index the item in the iterator/locator + * @param int|null $priority The priority of the item; the higher the number, the earlier the tagged service will be located in the iterator/locator */ public function __construct( public ?string $index = null, diff --git a/src/Symfony/Component/DependencyInjection/Compiler/PriorityTaggedServiceTrait.php b/src/Symfony/Component/DependencyInjection/Compiler/PriorityTaggedServiceTrait.php index 77a1d7ef8ffc2..e3a4eba275a75 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/PriorityTaggedServiceTrait.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/PriorityTaggedServiceTrait.php @@ -87,8 +87,7 @@ private function findAndSortTaggedServices(string|TaggedIteratorArgument $tagNam if (null === $index && null === $defaultIndex && $defaultPriorityMethod && $class) { $defaultIndex = PriorityTaggedServiceUtil::getDefault($container, $serviceId, $class, $defaultIndexMethod ?? 'getDefaultName', $tagName, $indexAttribute, $checkTaggedItem); } - $decorated = $definition->getTag('container.decorator')[0]['id'] ?? null; - $index = $index ?? $defaultIndex ?? $defaultIndex = $decorated ?? $serviceId; + $index ??= $defaultIndex ??= $definition->getTag('container.decorator')[0]['id'] ?? $serviceId; $services[] = [$priority, ++$i, $index, $serviceId, $class]; } diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ServiceLocatorTagPass.php b/src/Symfony/Component/DependencyInjection/Compiler/ServiceLocatorTagPass.php index 81c14ac5cc4d0..eedc0f484243c 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/ServiceLocatorTagPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/ServiceLocatorTagPass.php @@ -54,17 +54,41 @@ protected function processValue(mixed $value, bool $isRoot = false): mixed $value->setClass(ServiceLocator::class); } - $services = $value->getArguments()[0] ?? null; + $values = $value->getArguments()[0] ?? null; + $services = []; - if ($services instanceof TaggedIteratorArgument) { - $services = $this->findAndSortTaggedServices($services, $this->container); - } - - if (!\is_array($services)) { + if ($values instanceof TaggedIteratorArgument) { + foreach ($this->findAndSortTaggedServices($values, $this->container) as $k => $v) { + $services[$k] = new ServiceClosureArgument($v); + } + } elseif (!\is_array($values)) { throw new InvalidArgumentException(\sprintf('Invalid definition for service "%s": an array of references is expected as first argument when the "container.service_locator" tag is set.', $this->currentId)); + } else { + $i = 0; + + foreach ($values as $k => $v) { + if ($v instanceof ServiceClosureArgument) { + $services[$k] = $v; + continue; + } + + if ($i === $k) { + if ($v instanceof Reference) { + $k = (string) $v; + } + ++$i; + } elseif (\is_int($k)) { + $i = null; + } + + $services[$k] = new ServiceClosureArgument($v); + } + if (\count($services) === $i) { + ksort($services); + } } - $value->setArgument(0, self::map($services)); + $value->setArgument(0, $services); $id = '.service_locator.'.ContainerBuilder::hash($value); @@ -83,8 +107,12 @@ protected function processValue(mixed $value, bool $isRoot = false): mixed public static function register(ContainerBuilder $container, array $map, ?string $callerId = null): Reference { + foreach ($map as $k => $v) { + $map[$k] = new ServiceClosureArgument($v); + } + $locator = (new Definition(ServiceLocator::class)) - ->addArgument(self::map($map)) + ->addArgument($map) ->addTag('container.service_locator'); if (null !== $callerId && $container->hasDefinition($callerId)) { @@ -109,29 +137,4 @@ public static function register(ContainerBuilder $container, array $map, ?string return new Reference($id); } - - public static function map(array $services): array - { - $i = 0; - - foreach ($services as $k => $v) { - if ($v instanceof ServiceClosureArgument) { - continue; - } - - if ($i === $k) { - if ($v instanceof Reference) { - unset($services[$k]); - $k = (string) $v; - } - ++$i; - } elseif (\is_int($k)) { - $i = null; - } - - $services[$k] = new ServiceClosureArgument($v); - } - - return $services; - } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ServiceLocatorTagPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ServiceLocatorTagPassTest.php index 812b47c7a6f1f..9a93067756d50 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ServiceLocatorTagPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ServiceLocatorTagPassTest.php @@ -86,6 +86,26 @@ public function testProcessValue() $this->assertSame(CustomDefinition::class, \get_class($locator('inlines.service'))); } + public function testServiceListIsOrdered() + { + $container = new ContainerBuilder(); + + $container->register('bar', CustomDefinition::class); + $container->register('baz', CustomDefinition::class); + + $container->register('foo', ServiceLocator::class) + ->setArguments([[ + new Reference('baz'), + new Reference('bar'), + ]]) + ->addTag('container.service_locator') + ; + + (new ServiceLocatorTagPass())->process($container); + + $this->assertSame(['bar', 'baz'], array_keys($container->getDefinition('foo')->getArgument(0))); + } + public function testServiceWithKeyOverwritesPreviousInheritedKey() { $container = new ContainerBuilder(); @@ -170,6 +190,27 @@ public function testTaggedServices() $this->assertSame(TestDefinition2::class, $locator('baz')::class); } + public function testTaggedServicesKeysAreKept() + { + $container = new ContainerBuilder(); + + $container->register('bar', TestDefinition1::class)->addTag('test_tag', ['index' => 0]); + $container->register('baz', TestDefinition2::class)->addTag('test_tag', ['index' => 1]); + + $container->register('foo', ServiceLocator::class) + ->setArguments([new TaggedIteratorArgument('test_tag', 'index', null, true)]) + ->addTag('container.service_locator') + ; + + (new ServiceLocatorTagPass())->process($container); + + /** @var ServiceLocator $locator */ + $locator = $container->get('foo'); + + $this->assertSame(TestDefinition1::class, $locator(0)::class); + $this->assertSame(TestDefinition2::class, $locator(1)::class); + } + public function testIndexedByServiceIdWithDecoration() { $container = new ContainerBuilder(); @@ -201,15 +242,33 @@ public function testIndexedByServiceIdWithDecoration() static::assertInstanceOf(DecoratedService::class, $locator->get(Service::class)); } - public function testDefinitionOrderIsTheSame() + public function testServicesKeysAreKept() { $container = new ContainerBuilder(); $container->register('service-1'); $container->register('service-2'); + $container->register('service-3'); $locator = ServiceLocatorTagPass::register($container, [ - new Reference('service-2'), new Reference('service-1'), + 'service-2' => new Reference('service-2'), + 'foo' => new Reference('service-3'), + ]); + $locator = $container->getDefinition($locator); + $factories = $locator->getArguments()[0]; + + static::assertSame([0, 'service-2', 'foo'], array_keys($factories)); + } + + public function testDefinitionOrderIsTheSame() + { + $container = new ContainerBuilder(); + $container->register('service-1'); + $container->register('service-2'); + + $locator = ServiceLocatorTagPass::register($container, [ + 'service-2' => new Reference('service-2'), + 'service-1' => new Reference('service-1'), ]); $locator = $container->getDefinition($locator); $factories = $locator->getArguments()[0]; pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy