8000 [DependencyInjection] Auto exclude referencing service in `TaggedIter… · symfony/symfony@34a24ca · GitHub
[go: up one dir, main page]

Skip to content

Commit 34a24ca

Browse files
committed
[DependencyInjection] Auto exclude referencing service in TaggedIteratorArgument
1 parent e9870a4 commit 34a24ca

File tree

8 files changed

+55
-8
lines changed

8 files changed

+55
-8
lines changed

src/Symfony/Component/DependencyInjection/Argument/TaggedIteratorArgument.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ class TaggedIteratorArgument extends IteratorArgument
2424
private ?string $defaultPriorityMethod;
2525
private bool $needsIndexes;
2626
private array $exclude;
27+
private bool $excludeSelf = true;
2728

2829
/**
2930
* @param string $tag The name of the tag identifying the target services
@@ -32,8 +33,9 @@ class TaggedIteratorArgument extends IteratorArgument
3233
* @param bool $needsIndexes Whether indexes are required and should be generated when computing the map
3334
* @param string|null $defaultPriorityMethod The static method that should be called to get each service's priority when their tag doesn't define the "priority" attribute
3435
* @param array $exclude Services to exclude from the iterator
36+
* @param array $excludeSelf Whether to automatically exclude the referencing service from the iterator
3537
*/
36-
public function __construct(string $tag, string $indexAttribute = null, string $defaultIndexMethod = null, bool $needsIndexes = false, string $defaultPriorityMethod = null, array $exclude = [])
38+
public function __construct(string $tag, string $indexAttribute = null, string $defaultIndexMethod = null, bool $needsIndexes = false, string $defaultPriorityMethod = null, array $exclude = [], bool $excludeSelf = true)
3739
{
3840
parent::__construct([]);
3941

@@ -47,6 +49,7 @@ public function __construct(string $tag, string $indexAttribute = null, string $
4749
$this->needsIndexes = $needsIndexes;
4850
$this->defaultPriorityMethod = $defaultPriorityMethod ?: ($indexAttribute ? 'getDefault'.str_replace(' ', '', ucwords(preg_replace('/[^a-zA-Z0-9\x7f-\xff]++/', ' ', $indexAttribute))).'Priority' : null);
4951
$this->exclude = $exclude;
52+
$this->excludeSelf = $excludeSelf;
5053
}
5154

5255
public function getTag()
@@ -78,4 +81,9 @@ public function getExclude(): array
7881
{
7982
return $this->exclude;
8083
}
84+
85+
public function excludeSelf(): bool
86+
{
87+
return $this->excludeSelf;
88+
}
8189
}

src/Symfony/Component/DependencyInjection/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ CHANGELOG
2424
* Deprecate using numeric parameter names
2525
* Add support for tagged iterators/locators `exclude` option to the xml and yaml loaders/dumpers
2626
* Allow injecting `string $env` into php config closures
27+
* Add `excludeSelf` parameter to `TaggedIteratorArgument` with default value to `true`
28+
to control whether the referencing service should be automatically excluded from the iterator
2729

2830
6.1
2931
---

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,17 +37,16 @@ trait PriorityTaggedServiceTrait
3737
*
3838
* @return Reference[]
3939
*/
40-
private function findAndSortTaggedServices(string|TaggedIteratorArgument $tagName, ContainerBuilder $container): array
40+
private function findAndSortTaggedServices(string|TaggedIteratorArgument $tagName, ContainerBuilder $container, array $exclude = []): array
4141
{
42-
$exclude = [];
4342
$indexAttribute = $defaultIndexMethod = $needsIndexes = $defaultPriorityMethod = null;
4443

4544
if ($tagName instanceof TaggedIteratorArgument) {
4645
$indexAttribute = $tagName->getIndexAttribute();
4746
$defaultIndexMethod = $tagName->getDefaultIndexMethod();
4847
$needsIndexes = $tagName->needsIndexes();
4948
$defaultPriorityMethod = $tagName->getDefaultPriorityMethod() ?? 'getDefaultPriority';
50-
$exclude = $tagName->getExclude();
49+
$exclude = array_merge($exclude, $tagName->getExclude());
5150
$tagName = $tagName->getTag();
5251
}
5352

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,12 @@ protected function processValue(mixed $value, bool $isRoot = false): mixed
2828
return parent::processValue($value, $isRoot);
2929
}
3030

31-
$value->setValues($this->findAndSortTaggedServices($value, $this->container));
31+
$exclude = $value->getExclude();
32+
if ($value->excludeSelf()) {
33+
$exclude[] = $this->currentId;
34+
}
35+
36+
$value->setValues($this->findAndSortTaggedServices($value, $this->container, $exclude));
3237

3338
return $value;
3439
}

src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -550,7 +550,7 @@ private function getArgumentsAsPhp(\DOMElement $node, string $name, string $file
550550
$excludes = [$arg->getAttribute('exclude')];
551551
}
552552

553-
$arguments[$key] = new TaggedIteratorArgument($arg->getAttribute('tag'), $arg->getAttribute('index-by') ?: null, $arg->getAttribute('default-index-method') ?: null, $forLocator, $arg->getAttribute('default-priority-method') ?: null, $excludes);
553+
$arguments[$key] = new TaggedIteratorArgument($arg->getAttribute('tag'), $arg->getAttribute('index-by') ?: null, $arg->getAttribute('default-index-method') ?: null, $forLocator, $arg->getAttribute('default-priority-method') ?: null, $excludes, $arg->getAttribute('exclude-self') ?: true);
554554

555555
if ($forLocator) {
556556
$arguments[$key] = new ServiceLocatorArgument($arguments[$key]);

src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -824,11 +824,11 @@ private function resolveServices(mixed $value, string $file, bool $isParameter =
824824
$forLocator = 'tagged_locator' === $value->getTag();
825825

826826
if (\is_array($argument) && isset($argument['tag']) && $argument['tag']) {
827-
if ($diff = array_diff(array_keys($argument), $supportedKeys = ['tag', 'index_by', 'default_index_method', 'default_priority_method', 'exclude'])) {
827+
if ($diff = array_diff(array_keys($argument), $supportedKeys = ['tag', 'index_by', 'default_index_method', 'default_priority_method', 'exclude', 'exclude_self'])) {
828828
throw new InvalidArgumentException(sprintf('"!%s" tag contains unsupported key "%s"; supported ones are "%s".', $value->getTag(), implode('", "', $diff), implode('", "', $supportedKeys)));
829829
}
830830

831-
$argument = new TaggedIteratorArgument($argument['tag'], $argument['index_by'] ?? null, $argument['default_index_method'] ?? null, $forLocator, $argument['default_priority_method'] ?? null, (array) ($argument['exclude'] ?? null));
831+
$argument = new TaggedIteratorArgument($argument['tag'], $argument['index_by'] ?? null, $argument['default_index_method'] ?? null, $forLocator, $argument['default_priority_method'] ?? null, (array) ($argument['exclude'] ?? null), $argument['exclude_self'] ?? true);
832832
} elseif (\is_string($argument) && $argument) {
833833
$argument = new TaggedIteratorArgument($argument, null, null, $forLocator);
834834
} else {

src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,7 @@
302302
<xsd:attribute name="default-index-method" type="xsd:string" />
303303
<xsd:attribute name="default-priority-method" type="xsd:string" />
304304
<xsd:attribute name="exclude" type="xsd:string" />
305+
<xsd:attribute name="exclude-self" type="xsd:boolean" />
305306
</xsd:complexType>
306307

307308
<xsd:complexType name="call">

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

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,36 @@ public function testProcessWithIndexes()
5454
$expected->setValues(['1' => new TypedReference('service_a', 'stdClass'), '2' => new TypedReference('service_b', 'stdClass')]);
5555
$this->assertEquals($expected, $properties['foos']);
5656
}
57+
58+
public function testProcesWithAutoExcludeReferencingService()
59+
{
60+
$container = new ContainerBuilder();
61+
$container->register('service_a', 'stdClass')->addTag('foo', ['key' => '1']);
62+
$container->register('service_b', 'stdClass')->addTag('foo', ['key' => '2']);
63+
$container->register('service_c', 'stdClass')->addTag('foo', ['key' => '3'])->setProperty('foos', new TaggedIteratorArgument('foo', 'key'));
64+
65+
(new ResolveTaggedIteratorArgumentPass())->process($container);
66+
67+
$properties = $container->getDefinition('service_c')->getProperties();
68+
69+
$expected = new TaggedIteratorArgument('foo', 'key');
70+
$expected->setValues(['1' => new TypedReference('service_a', 'stdClass'), '2' => new TypedReference('service_b', 'stdClass')]);
71+
$this->assertEquals($expected, $properties['foos']);
72+
}
73+
74+
public function testProcesWithoutAutoExcludeReferencingService()
75+
{
76+
$container = new ContainerBuilder();
77+
$container->register('service_a', 'stdClass')->addTag('foo', ['key' => '1']);
78+
$container->register('service_b', 'stdClass')->addTag('foo', ['key' => '2']);
79+
$container->register('service_c', 'stdClass')->addTag('foo', ['key' => '3'])->setProperty('foos', new TaggedIteratorArgument(tag: 'foo', indexAttribute: 'key', excludeSelf: false));
80+
81+
(new ResolveTaggedIteratorArgumentPass())->process($container);
82+
83+
$properties = $container->getDefinition('service_c')->getProperties();
84+
85+
$expected = new TaggedIteratorArgument(tag: 'foo', indexAttribute: 'key', excludeSelf: false);
86+
$expected->setValues(['1' => new TypedReference('service_a', 'stdClass'), '2' => new TypedReference('service_b', 'stdClass'), '3' => new TypedReference('service_c', 'stdClass')]);
87+
$this->assertEquals($expected, $properties['foos']);
88+
}
5789
}

0 commit comments

Comments
 (0)
0