Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit a59ce75

Browse filesBrowse files
bug #35342 [DI] Fix support for multiple tags for locators and iterators (Alexandre Parent)
This PR was merged into the 4.4 branch. Discussion ---------- [DI] Fix support for multiple tags for locators and iterators | Q | A | ------------- | --- | Branch? | 4.3 | Bug fix? | no | New feature? | no | Deprecations? | no | Tickets | Fix #34462, Fix #35326 | License | MIT | Doc PR | none Fix PriorityTaggedServiceTrait::findAndSortTaggedServices to work with multiple explicitely tagged services as would be expected by !tagged_locator. Also reorganize PriorityTaggedServiceTrait::findAndSortTaggedServices to be simpler and easier to understand. Commits ------- 6fc91eb [DI] Fix support for multiple tags for locators and iterators
2 parents 84d32ac + 6fc91eb commit a59ce75
Copy full SHA for a59ce75

File tree

2 files changed

+123
-60
lines changed
Filter options

2 files changed

+123
-60
lines changed

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Compiler/PriorityTaggedServiceTrait.php
+61-58Lines changed: 61 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -54,78 +54,81 @@ private function findAndSortTaggedServices($tagName, ContainerBuilder $container
5454

5555
foreach ($container->findTaggedServiceIds($tagName, true) as $serviceId => $attributes) {
5656
$class = $r = null;
57-
$priority = 0;
58-
if (isset($attributes[0]['priority'])) {
59-
$priority = $attributes[0]['priority'];
60-
} elseif ($defaultPriorityMethod) {
61-
$class = $container->getDefinition($serviceId)->getClass();
62-
$class = $container->getParameterBag()->resolveValue($class) ?: null;
63-
64-
if (($r = $container->getReflectionClass($class)) && $r->hasMethod($defaultPriorityMethod)) {
65-
if (!($rm = $r->getMethod($defaultPriorityMethod))->isStatic()) {
66-
throw new InvalidArgumentException(sprintf('Method "%s::%s()" should be static: tag "%s" on service "%s".', $class, $defaultPriorityMethod, $tagName, $serviceId));
67-
}
68-
69-
if (!$rm->isPublic()) {
70-
throw new InvalidArgumentException(sprintf('Method "%s::%s()" should be public: tag "%s" on service "%s".', $class, $defaultPriorityMethod, $tagName, $serviceId));
71-
}
72-
73-
$priority = $rm->invoke(null);
74-
75-
if (!\is_int($priority)) {
76-
throw new InvalidArgumentException(sprintf('Method "%s::%s()" should return an integer, got %s: tag "%s" on service "%s".', $class, $defaultPriorityMethod, \gettype($priority), $tagName, $serviceId));
77-
}
78-
}
79-
}
80-
81-
if (null === $indexAttribute && !$needsIndexes) {
82-
$services[$priority][] = new Reference($serviceId);
83-
84-
continue;
85-
}
8657

87-
if (!$class) {
88-
$class = $container->getDefinition($serviceId)->getClass();
89-
$class = $container->getParameterBag()->resolveValue($class) ?: null;
90-
}
58+
$defaultPriority = null;
59+
$defaultIndex = null;
9160

92-
if (null !== $indexAttribute && isset($attributes[0][$indexAttribute])) {
93-
$services[$priority][$attributes[0][$indexAttribute]] = new TypedReference($serviceId, $class, ContainerBuilder::EXCEPTION_ON_INVALID_REFERENCE, $attributes[0][$indexAttribute]);
61+
foreach ($attributes as $attribute) {
62+
$index = $priority = null;
9463

95-
continue;
96-
}
64+
if (isset($attribute['priority'])) {
65+
$priority = $attribute['priority'];
66+
} elseif (null === $defaultPriority && $defaultPriorityMethod) {
67+
$class = $container->getDefinition($serviceId)->getClass();
68+
$class = $container->getParameterBag()->resolveValue($class) ?: null;
9769

98-
if (!$r && !$r = $container->getReflectionClass($class)) {
99-
throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $serviceId));
100-
}
70+
if (($r = ($r ?? $container->getReflectionClass($class))) && $r->hasMethod($defaultPriorityMethod)) {
71+
if (!($rm = $r->getMethod($defaultPriorityMethod))->isStatic()) {
72+
throw new InvalidArgumentException(sprintf('Method "%s::%s()" should be static: tag "%s" on service "%s".', $class, $defaultPriorityMethod, $tagName, $serviceId));
73+
}
10174

102-
$class = $r->name;
75+
if (!$rm->isPublic()) {
76+
throw new InvalidArgumentException(sprintf('Method "%s::%s()" should be public: tag "%s" on service "%s".', $class, $defaultPriorityMethod, $tagName, $serviceId));
77+
}
10378

104-
if (!$r->hasMethod($defaultIndexMethod)) {
105-
if ($needsIndexes) {
106-
$services[$priority][$serviceId] = new TypedReference($serviceId, $class);
79+
$defaultPriority = $rm->invoke(null);
10780

108-
continue;
81+
if (!\is_int($defaultPriority)) {
82+
throw new InvalidArgumentException(sprintf('Method "%s::%s()" should return an integer, got %s: tag "%s" on service "%s".', $class, $defaultPriorityMethod, \gettype($priority), $tagName, $serviceId));
83+
}
84+
}
10985
}
11086

111-
throw new InvalidArgumentException(sprintf('Method "%s::%s()" not found: tag "%s" on service "%s" is missing "%s" attribute.', $class, $defaultIndexMethod, $tagName, $serviceId, $indexAttribute));
112-
}
87+
$priority = $priority ?? $defaultPriority ?? 0;
88+
89+
if (null !== $indexAttribute && isset($attribute[$indexAttribute])) {
90+
$index = $attribute[$indexAttribute];
91+
} elseif (null === $defaultIndex && null === $indexAttribute && !$needsIndexes) {
92+
// With partially associative array, insertion to get next key is simpler.
93+
$services[$priority][] = null;
94+
end($services[$priority]);
95+
$defaultIndex = key($services[$priority]);
96+
} elseif (null === $defaultIndex && $defaultIndexMethod) {
97+
$class = $container->getDefinition($serviceId)->getClass();
98+
$class = $container->getParameterBag()->resolveValue($class) ?: null;
99+
100+
if (($r = ($r ?? $container->getReflectionClass($class))) && $r->hasMethod($defaultIndexMethod)) {
101+
if (!($rm = $r->getMethod($defaultIndexMethod))->isStatic()) {
102+
throw new InvalidArgumentException(sprintf('Method "%s::%s()" should be static: tag "%s" on service "%s" is missing "%s" attribute.', $class, $defaultIndexMethod, $tagName, $serviceId, $indexAttribute));
103+
}
104+
105+
if (!$rm->isPublic()) {
106+
throw new InvalidArgumentException(sprintf('Method "%s::%s()" should be public: tag "%s" on service "%s" is missing "%s" attribute.', $class, $defaultIndexMethod, $tagName, $serviceId, $indexAttribute));
107+
}
108+
109+
$defaultIndex = $rm->invoke(null);
110+
111+
if (!\is_string($defaultIndex)) {
112+
throw new InvalidArgumentException(sprintf('Method "%s::%s()" should return a string, got %s: tag "%s" on service "%s" is missing "%s" attribute.', $class, $defaultIndexMethod, \gettype($defaultIndex), $tagName, $serviceId, $indexAttribute));
113+
}
114+
}
113115

114-
if (!($rm = $r->getMethod($defaultIndexMethod))->isStatic()) {
115-
throw new InvalidArgumentException(sprintf('Method "%s::%s()" should be static: tag "%s" on service "%s" is missing "%s" attribute.', $class, $defaultIndexMethod, $tagName, $serviceId, $indexAttribute));
116-
}
116+
$defaultIndex = $defaultIndex ?? $serviceId;
117+
}
117118

118-
if (!$rm->isPublic()) {
119-
throw new InvalidArgumentException(sprintf('Method "%s::%s()" should be public: tag "%s" on service "%s" is missing "%s" attribute.', $class, $defaultIndexMethod, $tagName, $serviceId, $indexAttribute));
120-
}
119+
$index = $index ?? $defaultIndex;
121120

122-
$key = $rm->invoke(null);
121+
$reference = null;
122+
if (!$class || 'stdClass' === $class) {
123+
$reference = new Reference($serviceId);
124+
} elseif ($index === $serviceId) {
125+
$reference = new TypedReference($serviceId, $class);
126+
} else {
127+
$reference = new TypedReference($serviceId, $class, ContainerBuilder::EXCEPTION_ON_INVALID_REFERENCE, \is_string($index) ? $index : null);
128+
}
123129

124-
if (!\is_string($key)) {
125-
throw new InvalidArgumentException(sprintf('Method "%s::%s()" should return a string, got %s: tag "%s" on service "%s" is missing "%s" attribute.', $class, $defaultIndexMethod, \gettype($key), $tagName, $serviceId, $indexAttribute));
130+
$services[$priority][$index] = $reference;
126131
}
127-
128-
$services[$priority][$key] = new TypedReference($serviceId, $class, ContainerBuilder::EXCEPTION_ON_INVALID_REFERENCE, $key);
129132
}
130133

131134
if ($services) {

‎src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php
+62-2Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,32 @@ public function testTaggedServiceWithIndexAttributeAndDefaultMethod()
314314
$this->assertSame(['bar_tab_class_with_defaultmethod' => $container->get(BarTagClass::class), 'foo' => $container->get(FooTagClass::class)], $param);
315315
}
316316

317+
public function testTaggedIteratorWithMultipleIndexAttribute()
318+
{
319+
$container = new ContainerBuilder();
320+
$container->register(BarTagClass::class)
321+
->setPublic(true)
322+
->addTag('foo_bar', ['foo' => 'bar'])
323+
->addTag('foo_bar', ['foo' => 'bar_duplicate'])
324+
;
325+
$container->register(FooTagClass::class)
326+
->setPublic(true)
327+
->addTag('foo_bar')
328+
->addTag('foo_bar')
329+
;
330+
$container->register(FooBarTaggedClass::class)
331+
->addArgument(new TaggedIteratorArgument('foo_bar', 'foo'))
332+
->setPublic(true)
333+
;
334+
335+
$container->compile();
336+
337+
$s = $container->get(FooBarTaggedClass::class);
338+
339+
$param = iterator_to_array($s->getParam()->getIterator());
340+
$this->assertSame(['bar' => $container->get(BarTagClass::class), 'bar_duplicate' => $container->get(BarTagClass::class), 'foo_tag_class' => $container->get(FooTagClass::class)], $param);
341+
}
342+
317343
public function testTaggedServiceWithDefaultPriorityMethod()
318344
{
319345
$container = new ContainerBuilder();
@@ -350,7 +376,7 @@ public function testTaggedServiceLocatorWithIndexAttribute()
350376
->addTag('foo_bar')
351377
;
352378
$container->register('foo_bar_tagged', FooBarTaggedClass::class)
353-
->addArgument(new ServiceLocatorArgument(new TaggedIteratorArgument('foo_bar', 'foo')))
379+
->addArgument(new ServiceLocatorArgument(new TaggedIteratorArgument('foo_bar', 'foo', null, true)))
354380
->setPublic(true)
355381
;
356382

@@ -369,6 +395,40 @@ public function testTaggedServiceLocatorWithIndexAttribute()
369395
$this->assertSame(['bar' => $container->get('bar_tag'), 'foo_tag_class' => $container->get('foo_tag')], $same);
370396
}
371397

398+
public function testTaggedServiceLocatorWithMultipleIndexAttribute()
399+
{
400+
$container = new ContainerBuilder();
401+
$container->register('bar_tag', BarTagClass::class)
402+
->setPublic(true)
403+
->addTag('foo_bar', ['foo' => 'bar'])
404+
->addTag('foo_bar', ['foo' => 'bar_duplicate'])
405+
;
406+
$container->register('foo_tag', FooTagClass::class)
407+
->setPublic(true)
408+
->addTag('foo_bar')
409+
->addTag('foo_bar')
410+
;
411+
$container->register('foo_bar_tagged', FooBarTaggedClass::class)
412+
->addArgument(new ServiceLocatorArgument(new TaggedIteratorArgument('foo_bar', 'foo', null, true)))
413+
->setPublic(true)
414+
;
415+
416+
$container->compile();
417+
418+
$s = $container->get('foo_bar_tagged');
419+
420+
/** @var ServiceLocator $serviceLocator */
421+
$serviceLocator = $s->getParam();
422+
$this->assertTrue($s->getParam() instanceof ServiceLocator, sprintf('Wrong instance, should be an instance of ServiceLocator, %s given', \is_object($serviceLocator) ? \get_class($serviceLocator) : \gettype($serviceLocator)));
423+
424+
$same = [
425+
'bar' => $serviceLocator->get('bar'),
426+
'bar_duplicate' => $serviceLocator->get('bar_duplicate'),
427+
'foo_tag_class' => $serviceLocator->get('foo_tag_class'),
428+
];
429+
$this->assertSame(['bar' => $container->get('bar_tag'), 'bar_duplicate' => $container->get('bar_tag'), 'foo_tag_class' => $container->get('foo_tag')], $same);
430+
}
431+
372432
public function testTaggedServiceLocatorWithIndexAttributeAndDefaultMethod()
373433
{
374434
$container = new ContainerBuilder();
@@ -381,7 +441,7 @@ public function testTaggedServiceLocatorWithIndexAttributeAndDefaultMethod()
381441
->addTag('foo_bar', ['foo' => 'foo'])
382442
;
383443
$container->register('foo_bar_tagged', FooBarTaggedClass::class)
384-
->addArgument(new ServiceLocatorArgument(new TaggedIteratorArgument('foo_bar', 'foo', 'getFooBar')))
444+
->addArgument(new ServiceLocatorArgument(new TaggedIteratorArgument('foo_bar', 'foo', 'getFooBar', true)))
385445
->setPublic(true)
386446
;
387447

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.