From 250a2c8332d80af732ca19a967196d76dc94d80f Mon Sep 17 00:00:00 2001 From: Anthony MARTIN Date: Fri, 15 Feb 2019 15:50:49 +0100 Subject: [PATCH 1/2] [DI] Allow tagged_locator tag to be used as an argument Signed-off-by: Anthony MARTIN --- .../Argument/ServiceLocatorArgument.php | 22 ++++++ .../Argument/TaggedIteratorArgument.php | 2 - .../DependencyInjection/CHANGELOG.md | 1 + .../Compiler/ServiceLocatorTagPass.php | 7 ++ .../DependencyInjection/Dumper/XmlDumper.php | 14 +++- .../DependencyInjection/Dumper/YamlDumper.php | 12 +++ .../Configurator/ContainerConfigurator.php | 8 ++ .../Loader/XmlFileLoader.php | 7 ++ .../Loader/YamlFileLoader.php | 13 ++++ .../schema/dic/services/services-1.0.xsd | 1 + .../Tests/Compiler/IntegrationTest.php | 76 +++++++++++++++++-- .../PriorityTaggedServiceTraitTest.php | 2 +- .../Tests/Dumper/XmlDumperTest.php | 10 ++- .../Tests/Dumper/YamlDumperTest.php | 7 +- .../xml/services_with_tagged_arguments.xml | 3 + .../yaml/services_with_tagged_argument.yml | 5 +- .../Tests/Loader/XmlFileLoaderTest.php | 7 +- .../Tests/Loader/YamlFileLoaderTest.php | 9 ++- 18 files changed, 187 insertions(+), 19 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Argument/ServiceLocatorArgument.php b/src/Symfony/Component/DependencyInjection/Argument/ServiceLocatorArgument.php index 8214f8bb3a6c3..fcbf478c627f9 100644 --- a/src/Symfony/Component/DependencyInjection/Argument/ServiceLocatorArgument.php +++ b/src/Symfony/Component/DependencyInjection/Argument/ServiceLocatorArgument.php @@ -11,6 +11,8 @@ namespace Symfony\Component\DependencyInjection\Argument; +use Symfony\Component\DependencyInjection\Reference; + /** * Represents a closure acting as a service locator. * @@ -19,4 +21,24 @@ class ServiceLocatorArgument implements ArgumentInterface { use ReferenceSetArgumentTrait; + + private $taggedIteratorArgument; + + /** + * @param Reference[]|TaggedIteratorArgument $values + */ + public function __construct($values = []) + { + if ($values instanceof TaggedIteratorArgument) { + $this->taggedIteratorArgument = $values; + $this->values = []; + } else { + $this->setValues($values); + } + } + + public function getTaggedIteratorArgument(): ?TaggedIteratorArgument + { + return $this->taggedIteratorArgument; + } } diff --git a/src/Symfony/Component/DependencyInjection/Argument/TaggedIteratorArgument.php b/src/Symfony/Component/DependencyInjection/Argument/TaggedIteratorArgument.php index fabfb00451851..a3099686d16df 100644 --- a/src/Symfony/Component/DependencyInjection/Argument/TaggedIteratorArgument.php +++ b/src/Symfony/Component/DependencyInjection/Argument/TaggedIteratorArgument.php @@ -23,8 +23,6 @@ class TaggedIteratorArgument extends IteratorArgument private $defaultIndexMethod; /** - * TaggedIteratorArgument constructor. - * * @param string $tag The name of the tag identifying the target services * @param string|null $indexAttribute The name of the attribute that defines the key referencing each service in the tagged collection * @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 diff --git a/src/Symfony/Component/DependencyInjection/CHANGELOG.md b/src/Symfony/Component/DependencyInjection/CHANGELOG.md index 7390e4289f510..c8ef90f5bc1ef 100644 --- a/src/Symfony/Component/DependencyInjection/CHANGELOG.md +++ b/src/Symfony/Component/DependencyInjection/CHANGELOG.md @@ -9,6 +9,7 @@ CHANGELOG * added support for deprecating aliases * made `ContainerParametersResource` final and not implement `Serializable` anymore * added ability to define an index for a tagged collection + * added ability to define an index for services in an injected service locator argument 4.2.0 ----- diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ServiceLocatorTagPass.php b/src/Symfony/Component/DependencyInjection/Compiler/ServiceLocatorTagPass.php index e335307482aec..2030d3774cc17 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/ServiceLocatorTagPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/ServiceLocatorTagPass.php @@ -27,11 +27,18 @@ */ final class ServiceLocatorTagPass extends AbstractRecursivePass { + use PriorityTaggedServiceTrait; + protected function processValue($value, $isRoot = false) { if ($value instanceof ServiceLocatorArgument) { + if ($value->getTaggedIteratorArgument()) { + $value->setValues($this->findAndSortTaggedServices($value->getTaggedIteratorArgument(), $this->container)); + } + return self::register($this->container, $value->getValues()); } + if (!$value instanceof Definition || !$value->hasTag('container.service_locator')) { return parent::processValue($value, $isRoot); } diff --git a/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php index eb56becd8da09..5b9edd03510ba 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php @@ -298,8 +298,18 @@ private function convertParameters(array $parameters, $type, \DOMElement $parent $element->setAttribute('type', 'iterator'); $this->convertParameters($value->getValues(), $type, $element, 'key'); } elseif ($value instanceof ServiceLocatorArgument) { - $element->setAttribute('type', 'service_locator'); - $this->convertParameters($value->getValues(), $type, $element, 'key'); + if ($value->getTaggedIteratorArgument()) { + $element->setAttribute('type', 'tagged_locator'); + $element->setAttribute('tag', $value->getTaggedIteratorArgument()->getTag()); + $element->setAttribute('index-by', $value->getTaggedIteratorArgument()->getIndexAttribute()); + + if (null !== $value->getTaggedIteratorArgument()->getDefaultIndexMethod()) { + $element->setAttribute('default-index-method', $value->getTaggedIteratorArgument()->getDefaultIndexMethod()); + } + } else { + $element->setAttribute('type', 'service_locator'); + $this->convertParameters($value->getValues(), $type, $element, 'key'); + } } elseif ($value instanceof Reference) { $element->setAttribute('type', 'service'); $element->setAttribute('id', (string) $value); diff --git a/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php index 875ebbc0abc8b..b4c899379c4c4 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php @@ -252,6 +252,18 @@ private function dumpValue($value) $tag = 'iterator'; } elseif ($value instanceof ServiceLocatorArgument) { $tag = 'service_locator'; + if ($value->getTaggedIteratorArgument()) { + $taggedValueContent = [ + 'tag' => $value->getTaggedIteratorArgument()->getTag(), + 'index_by' => $value->getTaggedIteratorArgument()->getIndexAttribute(), + ]; + + if (null !== $value->getTaggedIteratorArgument()->getDefaultIndexMethod()) { + $taggedValueContent['default_index_method'] = $value->getTaggedIteratorArgument()->getDefaultIndexMethod(); + } + + return new TaggedValue('tagged_locator', $taggedValueContent); + } } else { throw new RuntimeException(sprintf('Unspecified Yaml tag for type "%s".', \get_class($value))); } diff --git a/src/Symfony/Component/DependencyInjection/Loader/Configurator/ContainerConfigurator.php b/src/Symfony/Component/DependencyInjection/Loader/Configurator/ContainerConfigurator.php index f75ba1be85790..d4b03fc2c177e 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/Configurator/ContainerConfigurator.php +++ b/src/Symfony/Component/DependencyInjection/Loader/Configurator/ContainerConfigurator.php @@ -121,6 +121,14 @@ function tagged(string $tag, string $indexAttribute = null, string $defaultIndex return new TaggedIteratorArgument($tag, $indexAttribute, $defaultIndexMethod); } +/** + * Creates a service locator by tag name. + */ +function tagged_locator(string $tag, string $indexAttribute, string $defaultIndexMethod = null): ServiceLocatorArgument +{ + return new ServiceLocatorArgument(new TaggedIteratorArgument($tag, $indexAttribute, $defaultIndexMethod)); +} + /** * Creates an expression. */ diff --git a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php index b5e076888fb1e..ced8b0142d25d 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php @@ -533,6 +533,13 @@ private function getArgumentsAsPhp(\DOMElement $node, $name, $file, $lowercase = throw new InvalidArgumentException(sprintf('Tag "<%s>" with type="service_locator" only accepts maps of type="service" references in "%s".', $name, $file)); } break; + case 'tagged_locator': + if (!$arg->getAttribute('tag') || !$arg->getAttribute('index-by')) { + throw new InvalidArgumentException(sprintf('Tag "<%s>" with type="tagged_locator" has no or empty "tag" or "index-by" attributes in "%s".', $name, $file)); + } + + $arguments[$key] = new ServiceLocatorArgument(new TaggedIteratorArgument($arg->getAttribute('tag'), $arg->getAttribute('index-by'), $arg->getAttribute('default-index-method') ?: null)); + break; case 'tagged': if (!$arg->getAttribute('tag')) { throw new InvalidArgumentException(sprintf('Tag "<%s>" with type="tagged" has no or empty "tag" attribute in "%s".', $name, $file)); diff --git a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php index 06fcbb4a91af1..4d9da4e314f9b 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php @@ -702,7 +702,9 @@ private function resolveServices($value, $file, $isParameter = false) if (!\is_array($argument)) { throw new InvalidArgumentException(sprintf('"!service_locator" tag only accepts maps in "%s".', $file)); } + $argument = $this->resolveServices($argument, $file, $isParameter); + try { return new ServiceLocatorArgument($argument); } catch (InvalidArgumentException $e) { @@ -724,6 +726,17 @@ private function resolveServices($value, $file, $isParameter = false) throw new InvalidArgumentException(sprintf('"!tagged" tags only accept a non empty string or an array with a key "tag" in "%s".', $file)); } + if ('tagged_locator' === $value->getTag()) { + if (\is_array($argument) && isset($argument['tag'], $argument['index_by']) && $argument['tag'] && $argument['index_by']) { + if ($diff = array_diff(array_keys($argument), ['tag', 'index_by', 'default_index_method'])) { + throw new InvalidArgumentException(sprintf('"!tagged_locator" tag contains unsupported key "%s"; supported ones are "tag", "index_by" and "default_index_method".', implode('"", "', $diff))); + } + + return new ServiceLocatorArgument(new TaggedIteratorArgument($argument['tag'], $argument['index_by'], $argument['default_index_method'] ?? null)); + } + + throw new InvalidArgumentException(sprintf('"!tagged_locator" tags only accept an array with at least keys "tag" and "index_by" in "%s".', $file)); + } if ('service' === $value->getTag()) { if ($isParameter) { throw new InvalidArgumentException(sprintf('Using an anonymous service in a parameter is not allowed in "%s".', $file)); diff --git a/src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd b/src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd index b14ffc8dcd212..841e807943174 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd +++ b/src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd @@ -264,6 +264,7 @@ + diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php index 1ba0a53eaa679..a2bbbe20cf12a 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php @@ -14,10 +14,12 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\Alias; +use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument; use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\DependencyInjection\ServiceLocator; use Symfony\Component\DependencyInjection\ServiceSubscriberInterface; use Symfony\Component\DependencyInjection\Tests\Fixtures\BarTagClass; use Symfony\Component\DependencyInjection\Tests\Fixtures\FooBarTaggedClass; @@ -242,15 +244,15 @@ public function getYamlCompileTests() public function testTaggedServiceWithIndexAttribute() { $container = new ContainerBuilder(); - $container->register(BarTagClass::class, BarTagClass::class) + $container->register(BarTagClass::class) ->setPublic(true) ->addTag('foo_bar', ['foo' => 'bar']) ; - $container->register(FooTagClass::class, FooTagClass::class) + $container->register(FooTagClass::class) ->setPublic(true) ->addTag('foo_bar') ; - $container->register(FooBarTaggedClass::class, FooBarTaggedClass::class) + $container->register(FooBarTaggedClass::class) ->addArgument(new TaggedIteratorArgument('foo_bar', 'foo')) ->setPublic(true) ; @@ -266,15 +268,15 @@ public function testTaggedServiceWithIndexAttribute() public function testTaggedServiceWithIndexAttributeAndDefaultMethod() { $container = new ContainerBuilder(); - $container->register(BarTagClass::class, BarTagClass::class) + $container->register(BarTagClass::class) ->setPublic(true) ->addTag('foo_bar') ; - $container->register(FooTagClass::class, FooTagClass::class) + $container->register(FooTagClass::class) ->setPublic(true) ->addTag('foo_bar', ['foo' => 'foo']) ; - $container->register(FooBarTaggedClass::class, FooBarTaggedClass::class) + $container->register(FooBarTaggedClass::class) ->addArgument(new TaggedIteratorArgument('foo_bar', 'foo', 'getFooBar')) ->setPublic(true) ; @@ -286,6 +288,68 @@ public function testTaggedServiceWithIndexAttributeAndDefaultMethod() $param = iterator_to_array($s->getParam()->getIterator()); $this->assertSame(['bar_tab_class_with_defaultmethod' => $container->get(BarTagClass::class), 'foo' => $container->get(FooTagClass::class)], $param); } + + public function testTaggedServiceLocatorWithIndexAttribute() + { + $container = new ContainerBuilder(); + $container->register(BarTagClass::class) + ->setPublic(true) + ->addTag('foo_bar', ['foo' => 'bar']) + ; + $container->register(FooTagClass::class) + ->setPublic(true) + ->addTag('foo_bar') + ; + $container->register(FooBarTaggedClass::class) + ->addArgument(new ServiceLocatorArgument(new TaggedIteratorArgument('foo_bar', 'foo'))) + ->setPublic(true) + ; + + $container->compile(); + + $s = $container->get(FooBarTaggedClass::class); + + /** @var ServiceLocator $serviceLocator */ + $serviceLocator = $s->getParam(); + $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))); + + $same = [ + 'bar' => $serviceLocator->get('bar'), + 'foo_tag_class' => $serviceLocator->get('foo_tag_class'), + ]; + $this->assertSame(['bar' => $container->get(BarTagClass::class), 'foo_tag_class' => $container->get(FooTagClass::class)], $same); + } + + public function testTaggedServiceLocatorWithIndexAttributeAndDefaultMethod() + { + $container = new ContainerBuilder(); + $container->register(BarTagClass::class) + ->setPublic(true) + ->addTag('foo_bar') + ; + $container->register(FooTagClass::class) + ->setPublic(true) + ->addTag('foo_bar', ['foo' => 'foo']) + ; + $container->register(FooBarTaggedClass::class) + ->addArgument(new ServiceLocatorArgument(new TaggedIteratorArgument('foo_bar', 'foo', 'getFooBar'))) + ->setPublic(true) + ; + + $container->compile(); + + $s = $container->get(FooBarTaggedClass::class); + + /** @var ServiceLocator $serviceLocator */ + $serviceLocator = $s->getParam(); + $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))); + + $same = [ + 'bar_tab_class_with_defaultmethod' => $serviceLocator->get('bar_tab_class_with_defaultmethod'), + 'foo' => $serviceLocator->get('foo'), + ]; + $this->assertSame(['bar_tab_class_with_defaultmethod' => $container->get(BarTagClass::class), 'foo' => $container->get(FooTagClass::class)], $same); + } } class ServiceSubscriberStub implements ServiceSubscriberInterface diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/PriorityTaggedServiceTraitTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/PriorityTaggedServiceTraitTest.php index 57ca9af427128..adf9696acd3ef 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/PriorityTaggedServiceTraitTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/PriorityTaggedServiceTraitTest.php @@ -93,6 +93,6 @@ class PriorityTaggedServiceTraitImplementation public function test($tagName, ContainerBuilder $container) { - return $this->findAndSortTaggedServices($tagName, $container); + return self::findAndSortTaggedServices($tagName, $container); } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/XmlDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/XmlDumperTest.php index 2c5615bc69bf7..cc80a69455b97 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/XmlDumperTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/XmlDumperTest.php @@ -13,6 +13,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Config\FileLocator; +use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument; use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -201,13 +202,18 @@ public function testDumpLoad() $this->assertStringEqualsFile(self::$fixturesPath.'/xml/services_dump_load.xml', $dumper->dump()); } - public function testTaggedArgument() + public function testTaggedArguments() { + $taggedIterator = new TaggedIteratorArgument('foo_tag', 'barfoo', 'foobar'); $container = new ContainerBuilder(); $container->register('foo', 'Foo')->addTag('foo_tag'); $container->register('foo_tagged_iterator', 'Bar') ->setPublic(true) - ->addArgument(new TaggedIteratorArgument('foo_tag', 'barfoo', 'foobar')) + ->addArgument($taggedIterator) + ; + $container->register('foo_tagged_locator', 'Bar') + ->setPublic(true) + ->addArgument(new ServiceLocatorArgument($taggedIterator)) ; $dumper = new XmlDumper($container); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/YamlDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/YamlDumperTest.php index 61a1aec5105dc..72901c855e414 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/YamlDumperTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/YamlDumperTest.php @@ -13,6 +13,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Config\FileLocator; +use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument; use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -96,11 +97,13 @@ public function testInlineServices() $this->assertStringEqualsFile(self::$fixturesPath.'/yaml/services_inline.yml', $dumper->dump()); } - public function testTaggedArgument() + public function testTaggedArguments() { + $taggedIterator = new TaggedIteratorArgument('foo', 'barfoo', 'foobar'); $container = new ContainerBuilder(); $container->register('foo_service', 'Foo')->addTag('foo'); - $container->register('foo_service_tagged', 'Bar')->addArgument(new TaggedIteratorArgument('foo', 'barfoo', 'foobar')); + $container->register('foo_service_tagged_iterator', 'Bar')->addArgument($taggedIterator); + $container->register('foo_service_tagged_locator', 'Bar')->addArgument(new ServiceLocatorArgument($taggedIterator)); $dumper = new YamlDumper($container); $this->assertStringEqualsFile(self::$fixturesPath.'/yaml/services_with_tagged_argument.yml', $dumper->dump()); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_with_tagged_arguments.xml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_with_tagged_arguments.xml index e979d5fc9be38..e3e51d352d837 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_with_tagged_arguments.xml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_with_tagged_arguments.xml @@ -8,6 +8,9 @@ + + + diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_tagged_argument.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_tagged_argument.yml index bf7cf06930d0c..5e071d327802e 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_tagged_argument.yml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_tagged_argument.yml @@ -8,9 +8,12 @@ services: class: Foo tags: - { name: foo } - foo_service_tagged: + foo_service_tagged_iterator: class: Bar arguments: [!tagged { tag: foo, index_by: barfoo, default_index_method: foobar }] + foo_service_tagged_locator: + class: Bar + arguments: [!tagged_locator { tag: foo, index_by: barfoo, default_index_method: foobar }] Psr\Container\ContainerInterface: alias: service_container public: false diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php index 20c80258e2686..3e326ed85ab4b 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php @@ -18,6 +18,7 @@ use Symfony\Component\Config\Resource\GlobResource; use Symfony\Component\DependencyInjection\Argument\BoundArgument; use Symfony\Component\DependencyInjection\Argument\IteratorArgument; +use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument; use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Dumper\PhpDumper; @@ -324,7 +325,11 @@ public function testParseTaggedArgumentsWithIndexBy() $this->assertCount(1, $container->getDefinition('foo')->getTag('foo_tag')); $this->assertCount(1, $container->getDefinition('foo_tagged_iterator')->getArguments()); - $this->assertEquals(new TaggedIteratorArgument('foo_tag', 'barfoo', 'foobar'), $container->getDefinition('foo_tagged_iterator')->getArgument(0)); + $this->assertCount(1, $container->getDefinition('foo_tagged_locator')->getArguments()); + + $taggedIterator = new TaggedIteratorArgument('foo_tag', 'barfoo', 'foobar'); + $this->assertEquals($taggedIterator, $container->getDefinition('foo_tagged_iterator')->getArgument(0)); + $this->assertEquals(new ServiceLocatorArgument($taggedIterator), $container->getDefinition('foo_tagged_locator')->getArgument(0)); } /** diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php index 7870a521a9dbe..0da99f437b7f8 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php @@ -18,6 +18,7 @@ use Symfony\Component\Config\Resource\GlobResource; use Symfony\Component\DependencyInjection\Argument\BoundArgument; use Symfony\Component\DependencyInjection\Argument\IteratorArgument; +use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument; use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Loader\IniFileLoader; @@ -287,8 +288,12 @@ public function testTaggedArgumentsWithIndex() $loader->load('services_with_tagged_argument.yml'); $this->assertCount(1, $container->getDefinition('foo_service')->getTag('foo')); - $this->assertCount(1, $container->getDefinition('foo_service_tagged')->getArguments()); - $this->assertEquals(new TaggedIteratorArgument('foo', 'barfoo', 'foobar'), $container->getDefinition('foo_service_tagged')->getArgument(0)); + $this->assertCount(1, $container->getDefinition('foo_service_tagged_iterator')->getArguments()); + $this->assertCount(1, $container->getDefinition('foo_service_tagged_locator')->getArguments()); + + $taggedIterator = new TaggedIteratorArgument('foo', 'barfoo', 'foobar'); + $this->assertEquals($taggedIterator, $container->getDefinition('foo_service_tagged_iterator')->getArgument(0)); + $this->assertEquals(new ServiceLocatorArgument($taggedIterator), $container->getDefinition('foo_service_tagged_locator')->getArgument(0)); } public function testNameOnlyTagsAreAllowedAsString() From cb3c56bc0c58abe076c67284a8da132db7697c08 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 7 Mar 2019 15:19:37 +0100 Subject: [PATCH 2/2] Support indexing tagged locators by FQCN as fallback --- .../Argument/TaggedIteratorArgument.php | 17 +++++---- .../Compiler/PriorityTaggedServiceTrait.php | 27 ++++++++++---- .../DependencyInjection/Dumper/XmlDumper.php | 32 ++++++----------- .../DependencyInjection/Dumper/YamlDumper.php | 35 +++++++------------ .../Configurator/ContainerConfigurator.php | 2 +- .../Loader/XmlFileLoader.php | 17 ++++----- .../Loader/YamlFileLoader.php | 23 ++++++------ .../Tests/Compiler/IntegrationTest.php | 26 ++++++++++++++ .../PriorityTaggedServiceTraitTest.php | 2 +- .../Tests/Loader/XmlFileLoaderTest.php | 2 ++ .../Tests/Loader/YamlFileLoaderTest.php | 2 ++ 11 files changed, 107 insertions(+), 78 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Argument/TaggedIteratorArgument.php b/src/Symfony/Component/DependencyInjection/Argument/TaggedIteratorArgument.php index a3099686d16df..f3b323ce4c2a0 100644 --- a/src/Symfony/Component/DependencyInjection/Argument/TaggedIteratorArgument.php +++ b/src/Symfony/Component/DependencyInjection/Argument/TaggedIteratorArgument.php @@ -21,22 +21,22 @@ class TaggedIteratorArgument extends IteratorArgument private $tag; private $indexAttribute; private $defaultIndexMethod; + private $useFqcnAsFallback = false; /** * @param string $tag The name of the tag identifying the target services * @param string|null $indexAttribute The name of the attribute that defines the key referencing each service in the tagged collection * @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 + * @param bool $useFqcnAsFallback Whether the FQCN of the service should be used as index when neither the attribute nor the method are defined */ - public function __construct(string $tag, string $indexAttribute = null, string $defaultIndexMethod = null) + public function __construct(string $tag, string $indexAttribute = null, string $defaultIndexMethod = null, bool $useFqcnAsFallback = false) { parent::__construct([]); $this->tag = $tag; - - if ($indexAttribute) { - $this->indexAttribute = $indexAttribute; - $this->defaultIndexMethod = $defaultIndexMethod ?: ('getDefault'.str_replace(' ', '', ucwords(preg_replace('/[^a-zA-Z0-9\x7f-\xff]++/', ' ', $indexAttribute))).'Name'); - } + $this->indexAttribute = $indexAttribute; + $this->defaultIndexMethod = $defaultIndexMethod ?: ('getDefault'.str_replace(' ', '', ucwords(preg_replace('/[^a-zA-Z0-9\x7f-\xff]++/', ' ', $indexAttribute ?? ''))).'Name'); + $this->useFqcnAsFallback = $useFqcnAsFallback; } public function getTag() @@ -53,4 +53,9 @@ public function getDefaultIndexMethod(): ?string { return $this->defaultIndexMethod; } + + public function useFqcnAsFallback(): bool + { + return $this->useFqcnAsFallback; + } } diff --git a/src/Symfony/Component/DependencyInjection/Compiler/PriorityTaggedServiceTrait.php b/src/Symfony/Component/DependencyInjection/Compiler/PriorityTaggedServiceTrait.php index f9046d3c3283b..3bf8e3be18be3 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/PriorityTaggedServiceTrait.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/PriorityTaggedServiceTrait.php @@ -15,6 +15,7 @@ use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\DependencyInjection\TypedReference; /** * Trait that allows a generic method to find and sort service by priority option in the tag. @@ -40,34 +41,48 @@ trait PriorityTaggedServiceTrait */ private function findAndSortTaggedServices($tagName, ContainerBuilder $container) { - $indexAttribute = $defaultIndexMethod = null; + $indexAttribute = $defaultIndexMethod = $useFqcnAsFallback = null; + if ($tagName instanceof TaggedIteratorArgument) { $indexAttribute = $tagName->getIndexAttribute(); $defaultIndexMethod = $tagName->getDefaultIndexMethod(); + $useFqcnAsFallback = $tagName->useFqcnAsFallback(); $tagName = $tagName->getTag(); } + $services = []; foreach ($container->findTaggedServiceIds($tagName, true) as $serviceId => $attributes) { $priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0; - if (null === $indexAttribute) { + if (null === $indexAttribute && !$useFqcnAsFallback) { $services[$priority][] = new Reference($serviceId); continue; } - if (isset($attributes[0][$indexAttribute])) { - $services[$priority][$attributes[0][$indexAttribute]] = new Reference($serviceId); + $class = $container->getDefinition($serviceId)->getClass(); + $class = $container->getParameterBag()->resolveValue($class) ?: null; + + if (null !== $indexAttribute && isset($attributes[0][$indexAttribute])) { + $services[$priority][$attributes[0][$indexAttribute]] = new TypedReference($serviceId, $class, ContainerBuilder::EXCEPTION_ON_INVALID_REFERENCE, $attributes[0][$indexAttribute]); continue; } - if (!$r = $container->getReflectionClass($class = $container->getDefinition($serviceId)->getClass())) { + if (!$r = $container->getReflectionClass($class)) { throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $serviceId)); } + $class = $r->name; + if (!$r->hasMethod($defaultIndexMethod)) { + if ($useFqcnAsFallback) { + $services[$priority][$class] = new TypedReference($serviceId, $class); + + continue; + } + throw new InvalidArgumentException(sprintf('Method "%s::%s()" not found: tag "%s" on service "%s" is missing "%s" attribute.', $class, $defaultIndexMethod, $tagName, $serviceId, $indexAttribute)); } @@ -85,7 +100,7 @@ private function findAndSortTaggedServices($tagName, ContainerBuilder $container 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)); } - $services[$priority][$key] = new Reference($serviceId); + $services[$priority][$key] = new TypedReference($serviceId, $class, ContainerBuilder::EXCEPTION_ON_INVALID_REFERENCE, $key); } if ($services) { diff --git a/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php index 5b9edd03510ba..57ac2675aeda4 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php @@ -280,36 +280,26 @@ private function convertParameters(array $parameters, $type, \DOMElement $parent if ($value instanceof ServiceClosureArgument) { $value = $value->getValues()[0]; } - if (\is_array($value)) { + if (\is_array($tag = $value)) { $element->setAttribute('type', 'collection'); $this->convertParameters($value, $type, $element, 'key'); - } elseif ($value instanceof TaggedIteratorArgument) { - $element->setAttribute('type', 'tagged'); - $element->setAttribute('tag', $value->getTag()); + } elseif ($value instanceof TaggedIteratorArgument || ($value instanceof ServiceLocatorArgument && $tag = $value->getTaggedIteratorArgument())) { + $element->setAttribute('type', $value instanceof TaggedIteratorArgument ? 'tagged' : 'tagged_locator'); + $element->setAttribute('tag', $tag->getTag()); - if (null !== $value->getIndexAttribute()) { - $element->setAttribute('index-by', $value->getIndexAttribute()); - } + if (null !== $tag->getIndexAttribute()) { + $element->setAttribute('index-by', $tag->getIndexAttribute()); - if (null !== $value->getDefaultIndexMethod()) { - $element->setAttribute('default-index-method', $value->getDefaultIndexMethod()); + if (null !== $tag->getDefaultIndexMethod()) { + $element->setAttribute('default-index-method', $tag->getDefaultIndexMethod()); + } } } elseif ($value instanceof IteratorArgument) { $element->setAttribute('type', 'iterator'); $this->convertParameters($value->getValues(), $type, $element, 'key'); } elseif ($value instanceof ServiceLocatorArgument) { - if ($value->getTaggedIteratorArgument()) { - $element->setAttribute('type', 'tagged_locator'); - $element->setAttribute('tag', $value->getTaggedIteratorArgument()->getTag()); - $element->setAttribute('index-by', $value->getTaggedIteratorArgument()->getIndexAttribute()); - - if (null !== $value->getTaggedIteratorArgument()->getDefaultIndexMethod()) { - $element->setAttribute('default-index-method', $value->getTaggedIteratorArgument()->getDefaultIndexMethod()); - } - } else { - $element->setAttribute('type', 'service_locator'); - $this->convertParameters($value->getValues(), $type, $element, 'key'); - } + $element->setAttribute('type', 'service_locator'); + $this->convertParameters($value->getValues(), $type, $element, 'key'); } elseif ($value instanceof Reference) { $element->setAttribute('type', 'service'); $element->setAttribute('id', (string) $value); diff --git a/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php index b4c899379c4c4..89dae636de023 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php @@ -232,38 +232,29 @@ private function dumpValue($value) $value = $value->getValues()[0]; } if ($value instanceof ArgumentInterface) { - if ($value instanceof TaggedIteratorArgument) { - if (null !== $value->getIndexAttribute()) { - $taggedValueContent = [ - 'tag' => $value->getTag(), - 'index_by' => $value->getIndexAttribute(), + $tag = $value; + + if ($value instanceof TaggedIteratorArgument || ($value instanceof ServiceLocatorArgument && $tag = $value->getTaggedIteratorArgument())) { + if (null === $tag->getIndexAttribute()) { + $content = $tag->getTag(); + } else { + $content = [ + 'tag' => $tag->getTag(), + 'index_by' => $tag->getIndexAttribute(), ]; - if (null !== $value->getDefaultIndexMethod()) { - $taggedValueContent['default_index_method'] = $value->getDefaultIndexMethod(); + if (null !== $tag->getDefaultIndexMethod()) { + $content['default_index_method'] = $tag->getDefaultIndexMethod(); } - - return new TaggedValue('tagged', $taggedValueContent); } - return new TaggedValue('tagged', $value->getTag()); + return new TaggedValue($value instanceof TaggedIteratorArgument ? 'tagged' : 'tagged_locator', $content); } + if ($value instanceof IteratorArgument) { $tag = 'iterator'; } elseif ($value instanceof ServiceLocatorArgument) { $tag = 'service_locator'; - if ($value->getTaggedIteratorArgument()) { - $taggedValueContent = [ - 'tag' => $value->getTaggedIteratorArgument()->getTag(), - 'index_by' => $value->getTaggedIteratorArgument()->getIndexAttribute(), - ]; - - if (null !== $value->getTaggedIteratorArgument()->getDefaultIndexMethod()) { - $taggedValueContent['default_index_method'] = $value->getTaggedIteratorArgument()->getDefaultIndexMethod(); - } - - return new TaggedValue('tagged_locator', $taggedValueContent); - } } else { throw new RuntimeException(sprintf('Unspecified Yaml tag for type "%s".', \get_class($value))); } diff --git a/src/Symfony/Component/DependencyInjection/Loader/Configurator/ContainerConfigurator.php b/src/Symfony/Component/DependencyInjection/Loader/Configurator/ContainerConfigurator.php index d4b03fc2c177e..87b066faf5030 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/Configurator/ContainerConfigurator.php +++ b/src/Symfony/Component/DependencyInjection/Loader/Configurator/ContainerConfigurator.php @@ -126,7 +126,7 @@ function tagged(string $tag, string $indexAttribute = null, string $defaultIndex */ function tagged_locator(string $tag, string $indexAttribute, string $defaultIndexMethod = null): ServiceLocatorArgument { - return new ServiceLocatorArgument(new TaggedIteratorArgument($tag, $indexAttribute, $defaultIndexMethod)); + return new ServiceLocatorArgument(new TaggedIteratorArgument($tag, $indexAttribute, $defaultIndexMethod, true)); } /** diff --git a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php index ced8b0142d25d..92c27e6ebf139 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php @@ -533,19 +533,20 @@ private function getArgumentsAsPhp(\DOMElement $node, $name, $file, $lowercase = throw new InvalidArgumentException(sprintf('Tag "<%s>" with type="service_locator" only accepts maps of type="service" references in "%s".', $name, $file)); } break; + case 'tagged': case 'tagged_locator': - if (!$arg->getAttribute('tag') || !$arg->getAttribute('index-by')) { - throw new InvalidArgumentException(sprintf('Tag "<%s>" with type="tagged_locator" has no or empty "tag" or "index-by" attributes in "%s".', $name, $file)); - } + $type = $arg->getAttribute('type'); + $forLocator = 'tagged_locator' === $type; - $arguments[$key] = new ServiceLocatorArgument(new TaggedIteratorArgument($arg->getAttribute('tag'), $arg->getAttribute('index-by'), $arg->getAttribute('default-index-method') ?: null)); - break; - case 'tagged': if (!$arg->getAttribute('tag')) { - throw new InvalidArgumentException(sprintf('Tag "<%s>" with type="tagged" has no or empty "tag" attribute in "%s".', $name, $file)); + throw new InvalidArgumentException(sprintf('Tag "<%s>" with type="%s" has no or empty "tag" attribute in "%s".', $name, $type, $file)); } - $arguments[$key] = new TaggedIteratorArgument($arg->getAttribute('tag'), $arg->getAttribute('index-by') ?: null, $arg->getAttribute('default-index-method') ?: null); + $arguments[$key] = new TaggedIteratorArgument($arg->getAttribute('tag'), $arg->getAttribute('index-by') ?: null, $arg->getAttribute('default-index-method') ?: null, $forLocator); + + if ($forLocator) { + $arguments[$key] = new ServiceLocatorArgument($arguments[$key]); + } break; case 'binary': if (false === $value = base64_decode($arg->nodeValue)) { diff --git a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php index 4d9da4e314f9b..ecd66dd276319 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php @@ -711,31 +711,28 @@ private function resolveServices($value, $file, $isParameter = false) throw new InvalidArgumentException(sprintf('"!service_locator" tag only accepts maps of "@service" references in "%s".', $file)); } } - if ('tagged' === $value->getTag()) { + if (\in_array($value->getTag(), ['tagged', 'tagged_locator'], true)) { + $forLocator = 'tagged_locator' === $value->getTag(); + if (\is_string($argument) && $argument) { - return new TaggedIteratorArgument($argument); + return new TaggedIteratorArgument($argument, null, null, $forLocator); } if (\is_array($argument) && isset($argument['tag']) && $argument['tag']) { if ($diff = array_diff(array_keys($argument), ['tag', 'index_by', 'default_index_method'])) { - throw new InvalidArgumentException(sprintf('"!tagged" tag contains unsupported key "%s"; supported ones are "tag", "index_by" and "default_index_method".', implode('"", "', $diff))); + throw new InvalidArgumentException(sprintf('"!%s" tag contains unsupported key "%s"; supported ones are "tag", "index_by" and "default_index_method".', $value->getTag(), implode('"", "', $diff))); } - return new TaggedIteratorArgument($argument['tag'], $argument['index_by'] ?? null, $argument['default_index_method'] ?? null); - } + $argument = new TaggedIteratorArgument($argument['tag'], $argument['index_by'], $argument['default_index_method'] ?? null, $forLocator); - throw new InvalidArgumentException(sprintf('"!tagged" tags only accept a non empty string or an array with a key "tag" in "%s".', $file)); - } - if ('tagged_locator' === $value->getTag()) { - if (\is_array($argument) && isset($argument['tag'], $argument['index_by']) && $argument['tag'] && $argument['index_by']) { - if ($diff = array_diff(array_keys($argument), ['tag', 'index_by', 'default_index_method'])) { - throw new InvalidArgumentException(sprintf('"!tagged_locator" tag contains unsupported key "%s"; supported ones are "tag", "index_by" and "default_index_method".', implode('"", "', $diff))); + if ($forLocator) { + $argument = new ServiceLocatorArgument($argument); } - return new ServiceLocatorArgument(new TaggedIteratorArgument($argument['tag'], $argument['index_by'], $argument['default_index_method'] ?? null)); + return $argument; } - throw new InvalidArgumentException(sprintf('"!tagged_locator" tags only accept an array with at least keys "tag" and "index_by" in "%s".', $file)); + throw new InvalidArgumentException(sprintf('"!%s" tags only accept a non empty string or an array with a key "tag" in "%s".', $value->getTag(), $file)); } if ('service' === $value->getTag()) { if ($isParameter) { diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php index a2bbbe20cf12a..feeb163edb023 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php @@ -350,6 +350,32 @@ public function testTaggedServiceLocatorWithIndexAttributeAndDefaultMethod() ]; $this->assertSame(['bar_tab_class_with_defaultmethod' => $container->get(BarTagClass::class), 'foo' => $container->get(FooTagClass::class)], $same); } + + public function testTaggedServiceLocatorWithFqcnFallback() + { + $container = new ContainerBuilder(); + $container->register(BarTagClass::class) + ->setPublic(true) + ->addTag('foo_bar') + ; + $container->register(FooBarTaggedClass::class) + ->addArgument(new ServiceLocatorArgument(new TaggedIteratorArgument('foo_bar', null, null, true))) + ->setPublic(true) + ; + + $container->compile(); + + $s = $container->get(FooBarTaggedClass::class); + + /** @var ServiceLocator $serviceLocator */ + $serviceLocator = $s->getParam(); + $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))); + + $same = [ + BarTagClass::class => $serviceLocator->get(BarTagClass::class), + ]; + $this->assertSame([BarTagClass::class => $container->get(BarTagClass::class)], $same); + } } class ServiceSubscriberStub implements ServiceSubscriberInterface diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/PriorityTaggedServiceTraitTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/PriorityTaggedServiceTraitTest.php index adf9696acd3ef..57ca9af427128 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/PriorityTaggedServiceTraitTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/PriorityTaggedServiceTraitTest.php @@ -93,6 +93,6 @@ class PriorityTaggedServiceTraitImplementation public function test($tagName, ContainerBuilder $container) { - return self::findAndSortTaggedServices($tagName, $container); + return $this->findAndSortTaggedServices($tagName, $container); } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php index 3e326ed85ab4b..681a43b332df3 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php @@ -329,6 +329,8 @@ public function testParseTaggedArgumentsWithIndexBy() $taggedIterator = new TaggedIteratorArgument('foo_tag', 'barfoo', 'foobar'); $this->assertEquals($taggedIterator, $container->getDefinition('foo_tagged_iterator')->getArgument(0)); + + $taggedIterator = new TaggedIteratorArgument('foo_tag', 'barfoo', 'foobar', true); $this->assertEquals(new ServiceLocatorArgument($taggedIterator), $container->getDefinition('foo_tagged_locator')->getArgument(0)); } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php index 0da99f437b7f8..83e034c482a81 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php @@ -293,6 +293,8 @@ public function testTaggedArgumentsWithIndex() $taggedIterator = new TaggedIteratorArgument('foo', 'barfoo', 'foobar'); $this->assertEquals($taggedIterator, $container->getDefinition('foo_service_tagged_iterator')->getArgument(0)); + + $taggedIterator = new TaggedIteratorArgument('foo', 'barfoo', 'foobar', true); $this->assertEquals(new ServiceLocatorArgument($taggedIterator), $container->getDefinition('foo_service_tagged_locator')->getArgument(0)); }