Skip to content

Commit 5400aac

Browse files
committed
[DependencyInjection] Fix ServiceLocatorTagPass indexes handling
1 parent 959b0ff commit 5400aac

File tree

4 files changed

+80
-39
lines changed

4 files changed

+80
-39
lines changed

src/Symfony/Component/DependencyInjection/Attribute/AsTaggedItem.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@
2020
class AsTaggedItem
2121
{
2222
/**
23-
* @param string|null $index The property or method to use to index the item in the locator
24-
* @param int|null $priority The priority of the item; the higher the number, the earlier the tagged service will be located in the locator
23+
* @param string|null $index The property or method to use to index the item in the iterator/locator
24+
* @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
2525
*/
2626
public function __construct(
2727
public ?string $index = null,

src/Symfony/Component/DependencyInjection/Compiler/PriorityTaggedServiceTrait.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,7 @@ private function findAndSortTaggedServices(string|TaggedIteratorArgument $tagNam
8787
if (null === $index && null === $defaultIndex && $defaultPriorityMethod && $class) {
8888
$defaultIndex = PriorityTaggedServiceUtil::getDefault($container, $serviceId, $class, $defaultIndexMethod ?? 'getDefaultName', $tagName, $indexAttribute, $checkTaggedItem);
8989
}
90-
$decorated = $definition->getTag('container.decorator')[0]['id'] ?? null;
91-
$index = $index ?? $defaultIndex ?? $defaultIndex = $decorated ?? $serviceId;
90+
$index ??= $defaultIndex ??= $definition->getTag('container.decorator')[0]['id'] ?? $serviceId;
9291

9392
$services[] = [$priority, ++$i, $index, $serviceId, $class];
9493
}

src/Symfony/Component/DependencyInjection/Compiler/ServiceLocatorTagPass.php

Lines changed: 36 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -54,17 +54,41 @@ protected function processValue(mixed $value, bool $isRoot = false): mixed
5454
$value->setClass(ServiceLocator::class);
5555
}
5656

57-
$services = $value->getArguments()[0] ?? null;
57+
$values = $value->getArguments()[0] ?? null;
58+
$services = [];
5859

59-
if ($services instanceof TaggedIteratorArgument) {
60-
$services = $this->findAndSortTaggedServices($services, $this->container);
61-
}
62-
63-
if (!\is_array($services)) {
60+
if ($values instanceof TaggedIteratorArgument) {
61+
foreach ($this->findAndSortTaggedServices($values, $this->container) as $k => $v) {
62+
$services[$k] = new ServiceClosureArgument($v);
63+
}
64+
} elseif (!\is_array($values)) {
6465
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));
66+
} else {
67+
$i = 0;
68+
69+
foreach ($values as $k => $v) {
70+
if ($v instanceof ServiceClosureArgument) {
71+
$services[$k] = $v;
72+
continue;
73+
}
74+
75+
if ($i === $k) {
76+
if ($v instanceof Reference) {
77+
$k = (string) $v;
78+
}
79+
++$i;
80+
} elseif (\is_int($k)) {
81+
$i = null;
82+
}
83+
84+
$services[$k] = new ServiceClosureArgument($v);
85+
}
86+
if (0 === $i) {
87+
ksort($services);
88+
}
6589
}
6690

67-
$value->setArgument(0, self::map($services));
91+
$value->setArgument(0, $services);
6892

6993
$id = '.service_locator.'.ContainerBuilder::hash($value);
7094

@@ -83,8 +107,12 @@ protected function processValue(mixed $value, bool $isRoot = false): mixed
83107

84108
public static function register(ContainerBuilder $container, array $map, ?string $callerId = null): Reference
85109
{
110+
foreach ($map as $k => $v) {
111+
$map[$k] = new ServiceClosureArgument($v);
112+
}
113+
86114
$locator = (new Definition(ServiceLocator::class))
87-
->addArgument(self::map($map))
115+
->addArgument($map)
88116
->addTag('container.service_locator');
89117

90118
if (null !== $callerId && $container->hasDefinition($callerId)) {
@@ -109,29 +137,4 @@ public static function register(ContainerBuilder $container, array $map, ?string
109137

110138
return new Reference($id);
111139
}
112-
113-
public static function map(array $services): array
114-
{
115-
$i = 0;
116-
117-
foreach ($services as $k => $v) {
118-
if ($v instanceof ServiceClosureArgument) {
119-
continue;
120-
}
121-
122-
if ($i === $k) {
123-
if ($v instanceof Reference) {
124-
unset($services[$k]);
125-
$k = (string) $v;
126-
}
127-
++$i;
128-
} elseif (\is_int($k)) {
129-
$i = null;
130-
}
131-
132-
$services[$k] = new ServiceClosureArgument($v);
133-
}
134-
135-
return $services;
136-
}
137140
}

src/Symfony/Component/DependencyInjection/Tests/Compiler/ServiceLocatorTagPassTest.php

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,27 @@ public function testTaggedServices()
170170
$this->assertSame(TestDefinition2::class, $locator('baz')::class);
171171
}
172172

173+
public function testTaggedServicesKeysAreKept()
174+
{
175+
$container = new ContainerBuilder();
176+
177+
$container->register('bar', TestDefinition1::class)->addTag('test_tag', ['index' => 0]);
178+
$container->register('baz', TestDefinition2::class)->addTag('test_tag', ['index' => 1]);
179+
180+
$container->register('foo', ServiceLocator::class)
181+
->setArguments([new TaggedIteratorArgument('test_tag', 'index', null, true)])
182+
->addTag('container.service_locator')
183+
;
184+
185+
(new ServiceLocatorTagPass())->process($container);
186+
187+
/** @var ServiceLocator $locator */
188+
$locator = $container->get('foo');
189+
190+
$this->assertSame(TestDefinition1::class, $locator(0)::class);
191+
$this->assertSame(TestDefinition2::class, $locator(1)::class);
192+
}
193+
173194
public function testIndexedByServiceIdWithDecoration()
174195
{
175196
$container = new ContainerBuilder();
@@ -201,15 +222,33 @@ public function testIndexedByServiceIdWithDecoration()
201222
static::assertInstanceOf(DecoratedService::class, $locator->get(Service::class));
202223
}
203224

204-
public function testDefinitionOrderIsTheSame()
225+
public function testServicesKeysAreKept()
205226
{
206227
$container = new ContainerBuilder();
207228
$container->register('service-1');
208229
$container->register('service-2');
230+
$container->register('service-3');
209231

210232
$locator = ServiceLocatorTagPass::register($container, [
211-
new Reference('service-2'),
212233
new Reference('service-1'),
234+
'service-2' => new Reference('service-2'),
235+
'foo' => new Reference('service-3'),
236+
]);
237+
$locator = $container->getDefinition($locator);
238+
$factories = $locator->getArguments()[0];
239+
240+
static::assertSame([0, 'service-2', 'foo'], array_keys($factories));
241+
}
242+
243+
public function testDefinitionOrderIsTheSame()
244+
{
245+
$container = new ContainerBuilder();
246+
$container->register('service-1');
247+
$container->register('service-2');
248+
249+
$locator = ServiceLocatorTagPass::register($container, [
250+
'service-2' => new Reference('service-2'),
251+
'service-1' => new Reference('service-1'),
213252
]);
214253
$locator = $container->getDefinition($locator);
215254
$factories = $locator->getArguments()[0];

0 commit comments

Comments
 (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