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

Skip to content

Commit e5570b4

Browse files
committed
[DependencyInjection] Auto exclude referencing service in TaggedIteratorArgument
1 parent e7482d7 commit e5570b4

File tree

5 files changed

+57
-11
lines changed

5 files changed

+57
-11
lines changed

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

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,18 @@ class TaggedIteratorArgument extends IteratorArgument
2424
private ?string $defaultPriorityMethod;
2525
private bool $needsIndexes;
2626
private array $exclude;
27+
private bool $autoExcludeReferencingService = true;
2728

2829
/**
29-
* @param string $tag The name of the tag identifying the target services
30-
* @param string|null $indexAttribute The name of the attribute that defines the key referencing each service in the tagged collection
31-
* @param string|null $defaultIndexMethod The static method that should be called to get each service's key when their tag doesn't define the previous attribute
32-
* @param bool $needsIndexes Whether indexes are required and should be generated when computing the map
33-
* @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
34-
* @param array $exclude Services to exclude from the iterator
30+
* @param string $tag The name of the tag identifying the target services
31+
* @param string|null $indexAttribute The name of the attribute that defines the key referencing each service in the tagged collection
32+
* @param string|null $defaultIndexMethod The static method that should be called to get each service's key when their tag doesn't define the previous attribute
33+
* @param bool $needsIndexes Whether indexes are required and should be generated when computing the map
34+
* @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
35+
* @param array $exclude Services to exclude from the iterator
36+
* @param array $autoExcludeReferencingService 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 $autoExcludeReferencingService = 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->autoExcludeReferencingService = $autoExcludeReferencingService;
5053
}
5154

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

src/Symfony/Component/DependencyInjection/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ CHANGELOG
77
* Add options `inline_factories` and `inline_class_loader` to `PhpDumper::dump()`
88
* Deprecate `PhpDumper` options `inline_factories_parameter` and `inline_class_loader_parameter`
99
* Add `RemoveBuildParametersPass`, which removes parameters starting with a dot during compilation
10+
* Add `autoExcludeReferencingService` parameter to `TaggedIteratorArgument` with default value to `true`
11+
to control whether the referencing service should be automatically excluded from the iterator if it holds the tag
1012

1113
6.2
1214
---

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 = $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->autoExcludeReferencingService() && !\in_array($this->currentId, $exclude, true) && $this->container->getDefinition($this->currentId)->hasTag($value->getTag())) {
33+
$exclude[] = $this->currentId;
34+
}
35+
36+
$value->setValues($this->findAndSortTaggedServices($value, $this->container, $exclude));
3237

3338
return $value;
3439
}

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', autoExcludeReferencingService: false));
80+
81+
(new ResolveTaggedIteratorArgumentPass())->process($container);
82+
83+
$properties = $container->getDefinition('service_c')->getProperties();
84+
85+
$expected = new TaggedIteratorArgument(tag: 'foo', indexAttribute: 'key', autoExcludeReferencingService: 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