diff --git a/src/Symfony/Component/DependencyInjection/Attribute/TaggedIterator.php b/src/Symfony/Component/DependencyInjection/Attribute/TaggedIterator.php index 81680abaa1849..d498f46470c15 100644 --- a/src/Symfony/Component/DependencyInjection/Attribute/TaggedIterator.php +++ b/src/Symfony/Component/DependencyInjection/Attribute/TaggedIterator.php @@ -17,6 +17,8 @@ class TaggedIterator public function __construct( public string $tag, public ?string $indexAttribute = null, + public ?string $defaultIndexMethod = null, + public ?string $defaultPriorityMethod = null, ) { } } diff --git a/src/Symfony/Component/DependencyInjection/Attribute/TaggedLocator.php b/src/Symfony/Component/DependencyInjection/Attribute/TaggedLocator.php index 3c1d8037093a0..4617e0f51dce3 100644 --- a/src/Symfony/Component/DependencyInjection/Attribute/TaggedLocator.php +++ b/src/Symfony/Component/DependencyInjection/Attribute/TaggedLocator.php @@ -17,6 +17,8 @@ class TaggedLocator public function __construct( public string $tag, public ?string $indexAttribute = null, + public ?string $defaultIndexMethod = null, + public ?string $defaultPriorityMethod = null, ) { } } diff --git a/src/Symfony/Component/DependencyInjection/CHANGELOG.md b/src/Symfony/Component/DependencyInjection/CHANGELOG.md index 46cd7f69ded0e..ad5dd88a1f520 100644 --- a/src/Symfony/Component/DependencyInjection/CHANGELOG.md +++ b/src/Symfony/Component/DependencyInjection/CHANGELOG.md @@ -3,7 +3,7 @@ CHANGELOG 5.4 --- - + * Add `$defaultIndexMethod` and `$defaultPriorityMethod` to `TaggedIterator` and `TaggedLocator` attributes * Add `service_closure()` to the PHP-DSL * Add support for autoconfigurable attributes on methods, properties and parameters * Make auto-aliases private by default diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php index 45cb642422349..b96219ac07894 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php @@ -223,8 +223,6 @@ private function autowireCalls(\ReflectionClass $reflectionClass, bool $isRoot, /** * Autowires the constructor or a method. * - * @return array - * * @throws AutowiringFailedException */ private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, array $arguments, bool $checkAttributes, int $methodIndex): array @@ -250,13 +248,13 @@ private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, a foreach ($parameter->getAttributes() as $attribute) { if (TaggedIterator::class === $attribute->getName()) { $attribute = $attribute->newInstance(); - $arguments[$index] = new TaggedIteratorArgument($attribute->tag, $attribute->indexAttribute); + $arguments[$index] = new TaggedIteratorArgument($attribute->tag, $attribute->indexAttribute, $attribute->defaultIndexMethod, false, $attribute->defaultPriorityMethod); break; } if (TaggedLocator::class === $attribute->getName()) { $attribute = $attribute->newInstance(); - $arguments[$index] = new ServiceLocatorArgument(new TaggedIteratorArgument($attribute->tag, $attribute->indexAttribute, null, true)); + $arguments[$index] = new ServiceLocatorArgument(new TaggedIteratorArgument($attribute->tag, $attribute->indexAttribute, $attribute->defaultIndexMethod, true, $attribute->defaultPriorityMethod)); break; } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php index ceb199ac81990..9e8cf0d97bcf5 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php @@ -33,9 +33,15 @@ use Symfony\Component\DependencyInjection\Tests\Fixtures\FooBarTaggedForDefaultPriorityClass; use Symfony\Component\DependencyInjection\Tests\Fixtures\FooTagClass; use Symfony\Component\DependencyInjection\Tests\Fixtures\IteratorConsumer; +use Symfony\Component\DependencyInjection\Tests\Fixtures\IteratorConsumerWithDefaultIndexMethod; +use Symfony\Component\DependencyInjection\Tests\Fixtures\IteratorConsumerWithDefaultIndexMethodAndWithDefaultPriorityMethod; +use Symfony\Component\DependencyInjection\Tests\Fixtures\IteratorConsumerWithDefaultPriorityMethod; use Symfony\Component\DependencyInjection\Tests\Fixtures\LocatorConsumer; use Symfony\Component\DependencyInjection\Tests\Fixtures\LocatorConsumerConsumer; use Symfony\Component\DependencyInjection\Tests\Fixtures\LocatorConsumerFactory; +use Symfony\Component\DependencyInjection\Tests\Fixtures\LocatorConsumerWithDefaultIndexMethod; +use Symfony\Component\DependencyInjection\Tests\Fixtures\LocatorConsumerWithDefaultIndexMethodAndWithDefaultPriorityMethod; +use Symfony\Component\DependencyInjection\Tests\Fixtures\LocatorConsumerWithDefaultPriorityMethod; use Symfony\Component\DependencyInjection\Tests\Fixtures\LocatorConsumerWithoutIndex; use Symfony\Component\DependencyInjection\Tests\Fixtures\TaggedService1; use Symfony\Component\DependencyInjection\Tests\Fixtures\TaggedService2; @@ -354,30 +360,85 @@ public function testTaggedServiceWithIndexAttributeAndDefaultMethodConfiguredVia $this->assertSame(['bar_tab_class_with_defaultmethod' => $container->get(BarTagClass::class), 'foo' => $container->get(FooTagClass::class)], $param); } - public function testTaggedIteratorWithMultipleIndexAttribute() + /** + * @requires PHP 8 + */ + public function testTaggedIteratorWithDefaultIndexMethodConfiguredViaAttribute() { $container = new ContainerBuilder(); $container->register(BarTagClass::class) ->setPublic(true) - ->addTag('foo_bar', ['foo' => 'bar']) - ->addTag('foo_bar', ['foo' => 'bar_duplicate']) + ->addTag('foo_bar') ; $container->register(FooTagClass::class) ->setPublic(true) ->addTag('foo_bar') + ; + $container->register(IteratorConsumerWithDefaultIndexMethod::class) + ->setAutowired(true) + ->setPublic(true) + ; + + $container->compile(); + + $s = $container->get(IteratorConsumerWithDefaultIndexMethod::class); + + $param = iterator_to_array($s->getParam()->getIterator()); + $this->assertSame(['bar_tag_class' => $container->get(BarTagClass::class), 'foo_tag_class' => $container->get(FooTagClass::class)], $param); + } + + /** + * @requires PHP 8 + */ + public function testTaggedIteratorWithDefaultPriorityMethodConfiguredViaAttribute() + { + $container = new ContainerBuilder(); + $container->register(BarTagClass::class) + ->setPublic(true) ->addTag('foo_bar') ; - $container->register(FooBarTaggedClass::class) - ->addArgument(new TaggedIteratorArgument('foo_bar', 'foo')) + $container->register(FooTagClass::class) + ->setPublic(true) + ->addTag('foo_bar') + ; + $container->register(IteratorConsumerWithDefaultPriorityMethod::class) + ->setAutowired(true) ->setPublic(true) ; $container->compile(); - $s = $container->get(FooBarTaggedClass::class); + $s = $container->get(IteratorConsumerWithDefaultPriorityMethod::class); + + $param = iterator_to_array($s->getParam()->getIterator()); + $this->assertSame([0 => $container->get(FooTagClass::class), 1 => $container->get(BarTagClass::class)], $param); + } + + /** + * @requires PHP 8 + */ + public function testTaggedIteratorWithDefaultIndexMethodAndWithDefaultPriorityMethodConfiguredViaAttribute() + { + $container = new ContainerBuilder(); + $container->register(BarTagClass::class) + ->setPublic(true) + ->addTag('foo_bar') + ; + $container->register(FooTagClass::class) + ->setPublic(true) + ->addTag('foo_bar') + ; + $container->register(IteratorConsumerWithDefaultIndexMethodAndWithDefaultPriorityMethod::class) + ->setAutowired(true) + ->setPublic(true) + ; + + $container->compile(); + + $s = $container->get(IteratorConsumerWithDefaultIndexMethodAndWithDefaultPriorityMethod::class); $param = iterator_to_array($s->getParam()->getIterator()); - $this->assertSame(['bar' => $container->get(BarTagClass::class), 'bar_duplicate' => $container->get(BarTagClass::class), 'foo_tag_class' => $container->get(FooTagClass::class)], $param); + $this->assertSame(['foo_tag_class' => $container->get(FooTagClass::class), 'bar_tag_class' => $container->get(BarTagClass::class)], $param); } /** @@ -438,6 +499,103 @@ public function testTaggedLocatorConfiguredViaAttributeWithoutIndex() self::assertSame($container->get(FooTagClass::class), $locator->get(FooTagClass::class)); } + /** + * @requires PHP 8 + */ + public function testTaggedLocatorWithDefaultIndexMethodConfiguredViaAttribute() + { + $container = new ContainerBuilder(); + $container->register(BarTagClass::class) + ->setPublic(true) + ->addTag('foo_bar') + ; + $container->register(FooTagClass::class) + ->setPublic(true) + ->addTag('foo_bar') + ; + $container->register(LocatorConsumerWithDefaultIndexMethod::class) + ->setAutowired(true) + ->setPublic(true) + ; + + $container->compile(); + + /** @var LocatorConsumerWithoutIndex $s */ + $s = $container->get(LocatorConsumerWithDefaultIndexMethod::class); + + $locator = $s->getLocator(); + self::assertSame($container->get(BarTagClass::class), $locator->get('bar_tag_class')); + self::assertSame($container->get(FooTagClass::class), $locator->get('foo_tag_class')); + } + + /** + * @requires PHP 8 + */ + public function testTaggedLocatorWithDefaultPriorityMethodConfiguredViaAttribute() + { + $container = new ContainerBuilder(); + $container->register(BarTagClass::class) + ->setPublic(true) + ->addTag('foo_bar') + ; + $container->register(FooTagClass::class) + ->setPublic(true) + ->addTag('foo_bar') + ; + $container->register(LocatorConsumerWithDefaultPriorityMethod::class) + ->setAutowired(true) + ->setPublic(true) + ; + + $container->compile(); + + /** @var LocatorConsumerWithoutIndex $s */ + $s = $container->get(LocatorConsumerWithDefaultPriorityMethod::class); + + $locator = $s->getLocator(); + + // We need to check priority of instances in the factories + $factories = (new \ReflectionClass($locator))->getProperty('factories'); + $factories->setAccessible(true); + + self::assertSame([FooTagClass::class, BarTagClass::class], array_keys($factories->getValue($locator))); + } + + /** + * @requires PHP 8 + */ + public function testTaggedLocatorWithDefaultIndexMethodAndWithDefaultPriorityMethodConfiguredViaAttribute() + { + $container = new ContainerBuilder(); + $container->register(BarTagClass::class) + ->setPublic(true) + ->addTag('foo_bar') + ; + $container->register(FooTagClass::class) + ->setPublic(true) + ->addTag('foo_bar') + ; + $container->register(LocatorConsumerWithDefaultIndexMethodAndWithDefaultPriorityMethod::class) + ->setAutowired(true) + ->setPublic(true) + ; + + $container->compile(); + + /** @var LocatorConsumerWithoutIndex $s */ + $s = $container->get(LocatorConsumerWithDefaultIndexMethodAndWithDefaultPriorityMethod::class); + + $locator = $s->getLocator(); + + // We need to check priority of instances in the factories + $factories = (new \ReflectionClass($locator))->getProperty('factories'); + $factories->setAccessible(true); + + self::assertSame(['foo_tag_class', 'bar_tag_class'], array_keys($factories->getValue($locator))); + self::assertSame($container->get(BarTagClass::class), $locator->get('bar_tag_class')); + self::assertSame($container->get(FooTagClass::class), $locator->get('foo_tag_class')); + } + /** * @requires PHP 8 */ diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/IteratorConsumerWithDefaultIndexMethod.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/IteratorConsumerWithDefaultIndexMethod.php new file mode 100644 index 0000000000000..9344b575eea79 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/IteratorConsumerWithDefaultIndexMethod.php @@ -0,0 +1,19 @@ +param; + } +} diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/IteratorConsumerWithDefaultIndexMethodAndWithDefaultPriorityMethod.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/IteratorConsumerWithDefaultIndexMethodAndWithDefaultPriorityMethod.php new file mode 100644 index 0000000000000..f0fd6f68eb72b --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/IteratorConsumerWithDefaultIndexMethodAndWithDefaultPriorityMethod.php @@ -0,0 +1,19 @@ +param; + } +} diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/IteratorConsumerWithDefaultPriorityMethod.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/IteratorConsumerWithDefaultPriorityMethod.php new file mode 100644 index 0000000000000..fe78f9c6d0b61 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/IteratorConsumerWithDefaultPriorityMethod.php @@ -0,0 +1,19 @@ +param; + } +} diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/LocatorConsumerWithDefaultIndexMethod.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/LocatorConsumerWithDefaultIndexMethod.php new file mode 100644 index 0000000000000..6519e4393a68e --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/LocatorConsumerWithDefaultIndexMethod.php @@ -0,0 +1,20 @@ +locator; + } +} diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/LocatorConsumerWithDefaultIndexMethodAndWithDefaultPriorityMethod.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/LocatorConsumerWithDefaultIndexMethodAndWithDefaultPriorityMethod.php new file mode 100644 index 0000000000000..f809a8b36ca55 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/LocatorConsumerWithDefaultIndexMethodAndWithDefaultPriorityMethod.php @@ -0,0 +1,20 @@ +locator; + } +} diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/LocatorConsumerWithDefaultPriorityMethod.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/LocatorConsumerWithDefaultPriorityMethod.php new file mode 100644 index 0000000000000..0fedc2b268089 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/LocatorConsumerWithDefaultPriorityMethod.php @@ -0,0 +1,20 @@ +locator; + } +}