Skip to content

Commit ed131b4

Browse files
author
Anthony MARTIN
committed
[DI] change name to tag + add XMl support + adding yaml/xml tests
1 parent 453b01a commit ed131b4

16 files changed

+218
-6
lines changed

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

+7
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@ class TaggedIteratorArgument extends IteratorArgument
2222
private $indexAttribute;
2323
private $defaultIndexMethod;
2424

25+
/**
26+
* TaggedIteratorArgument constructor.
27+
*
28+
* @param string $tag tag name
29+
* @param string|null $indexAttribute an attribute name on the tag to get the index name
30+
* @param string|null $defaultIndexMethod a public static method on tagged services to get theirs index names if no attribute corresponding to the $indexAttribute is set on the tag
31+
*/
2532
public function __construct(string $tag, string $indexAttribute = null, string $defaultIndexMethod = null)
2633
{
2734
parent::__construct([]);

src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php

+8
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,14 @@ private function convertParameters(array $parameters, $type, \DOMElement $parent
286286
} elseif ($value instanceof TaggedIteratorArgument) {
287287
$element->setAttribute('type', 'tagged');
288288
$element->setAttribute('tag', $value->getTag());
289+
290+
if (null !== $value->getIndexAttribute()) {
291+
$element->setAttribute('index-by', $value->getIndexAttribute());
292+
}
293+
294+
if (null !== $value->getDefaultIndexMethod()) {
295+
$element->setAttribute('default-index-method', $value->getDefaultIndexMethod());
296+
}
289297
} elseif ($value instanceof IteratorArgument) {
290298
$element->setAttribute('type', 'iterator');
291299
$this->convertParameters($value->getValues(), $type, $element, 'key');

src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php

+13
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,19 @@ private function dumpValue($value)
233233
}
234234
if ($value instanceof ArgumentInterface) {
235235
if ($value instanceof TaggedIteratorArgument) {
236+
if (null !== $value->getIndexAttribute()) {
237+
$taggedValueContent = [
238+
'tag' => $value->getTag(),
239+
'index_by' => $value->getIndexAttribute(),
240+
];
241+
242+
if (null !== $value->getDefaultIndexMethod()) {
243+
$taggedValueContent['default_index_method'] = $value->getDefaultIndexMethod();
244+
}
245+
246+
return new TaggedValue('tagged', $taggedValueContent);
247+
}
248+
236249
return new TaggedValue('tagged', $value->getTag());
237250
}
238251
if ($value instanceof IteratorArgument) {

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -537,7 +537,8 @@ private function getArgumentsAsPhp(\DOMElement $node, $name, $file, $lowercase =
537537
if (!$arg->getAttribute('tag')) {
538538
throw new InvalidArgumentException(sprintf('Tag "<%s>" with type="tagged" has no or empty "tag" attribute in "%s".', $name, $file));
539539
}
540-
$arguments[$key] = new TaggedIteratorArgument($arg->getAttribute('tag'));
540+
541+
$arguments[$key] = new TaggedIteratorArgument($arg->getAttribute('tag'), $arg->getAttribute('index-by') ?: null, $arg->getAttribute('default-index-method') ?: null);
541542
break;
542543
case 'binary':
543544
if (false === $value = base64_decode($arg->nodeValue)) {

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

+7-5
Original file line numberDiff line numberDiff line change
@@ -713,14 +713,16 @@ private function resolveServices($value, $file, $isParameter = false)
713713
if (\is_string($argument) && $argument) {
714714
return new TaggedIteratorArgument($argument);
715715
}
716-
if (\is_array($argument) && isset($argument['name']) && $argument['name']) {
717-
if (array_diff(array_keys($argument), ['name', 'index_by', 'default_index_method'])) {
718-
throw new InvalidArgumentException('"!tagged" tag contains unsupported keys. Supported are: "name, index_by, default_index_method".');
716+
717+
if (\is_array($argument) && isset($argument['tag']) && $argument['tag']) {
718+
if ($diff = array_diff(array_keys($argument), ['tag', 'index_by', 'default_index_method'])) {
719+
throw new InvalidArgumentException(sprintf('"!tagged" tag contains unsupported key "%s"; supported ones are "tag", "index_by" and "default_index_method".', implode(', ', $diff)));
719720
}
720721

721-
return new TaggedIteratorArgument($argument['name'], $argument['index_by'] ?? null, $argument['default_index_method'] ?? null);
722+
return new TaggedIteratorArgument($argument['tag'], $argument['index_by'] ?? null, $argument['default_index_method'] ?? null);
722723
}
723-
throw new InvalidArgumentException(sprintf('"!tagged" tag only accepts a non empty string or an array with a key "name" in "%s".', $file));
724+
725+
throw new InvalidArgumentException(sprintf('"!tagged" tags only accept a non empty string or an array with a key "tag" in "%s".', $file));
724726
}
725727
if ('service' === $value->getTag()) {
726728
if ($isParameter) {

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

+2
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,8 @@
234234
<xsd:attribute name="index" type="xsd:integer" />
235235
<xsd:attribute name="on-invalid" type="invalid_sequence" />
236236
<xsd:attribute name="tag" type="xsd:string" />
237+
<xsd:attribute name="index-by" type="xsd:string" />
238+
<xsd:attribute name="default-index-method" type="xsd:string" />
237239
</xsd:complexType>
238240

239241
<xsd:complexType name="call">

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

+52
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,14 @@
1414
use PHPUnit\Framework\TestCase;
1515
use Symfony\Component\Config\FileLocator;
1616
use Symfony\Component\DependencyInjection\Alias;
17+
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
1718
use Symfony\Component\DependencyInjection\ContainerBuilder;
1819
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
1920
use Symfony\Component\DependencyInjection\Reference;
2021
use Symfony\Component\DependencyInjection\ServiceSubscriberInterface;
22+
use Symfony\Component\DependencyInjection\Tests\Fixtures\BarTagClass;
23+
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooBarTaggedClass;
24+
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooTagClass;
2125

2226
/**
2327
* This class tests the integration of the different compiler passes.
@@ -234,6 +238,54 @@ public function getYamlCompileTests()
234238
$container,
235239
];
236240
}
241+
242+
public function testTaggedServiceWithIndexAttribute()
243+
{
244+
$container = new ContainerBuilder();
245+
$container->register(BarTagClass::class, BarTagClass::class)
246+
->setPublic(true)
247+
->addTag('foo_bar', ['foo' => 'bar'])
248+
;
249+
$container->register(FooTagClass::class, FooTagClass::class)
250+
->setPublic(true)
251+
->addTag('foo_bar')
252+
;
253+
$container->register(FooBarTaggedClass::class, FooBarTaggedClass::class)
254+
->addArgument(new TaggedIteratorArgument('foo_bar', 'foo'))
255+
->setPublic(true)
256+
;
257+
258+
$container->compile();
259+
260+
$s = $container->get(FooBarTaggedClass::class);
261+
262+
$param = iterator_to_array($s->getParam()->getIterator());
263+
$this->assertSame(['bar' => $container->get(BarTagClass::class), 'foo_tag_class' => $container->get(FooTagClass::class)], $param);
264+
}
265+
266+
public function testTaggedServiceWithIndexAttributeAndDefaultMethod()
267+
{
268+
$container = new ContainerBuilder();
269+
$container->register(BarTagClass::class, BarTagClass::class)
270+
->setPublic(true)
271+
->addTag('foo_bar')
272+
;
273+
$container->register(FooTagClass::class, FooTagClass::class)
274+
->setPublic(true)
275+
->addTag('foo_bar', ['foo' => 'foo'])
276+
;
277+
$container->register(FooBarTaggedClass::class, FooBarTaggedClass::class)
278+
->addArgument(new TaggedIteratorArgument('foo_bar', 'foo', 'getFooBar'))
279+
->setPublic(true)
280+
;
281+
282+
$container->compile();
283+
284+
$s = $container->get(FooBarTaggedClass::class);
285+
286+
$param = iterator_to_array($s->getParam()->getIterator());
287+
$this->assertSame(['bar_tab_class_with_defaultmethod' => $container->get(BarTagClass::class), 'foo' => $container->get(FooTagClass::class)], $param);
288+
}
237289
}
238290

239291
class ServiceSubscriberStub implements ServiceSubscriberInterface

src/Symfony/Component/DependencyInjection/Tests/Dumper/XmlDumperTest.php

+14
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use PHPUnit\Framework\TestCase;
1515
use Symfony\Component\Config\FileLocator;
16+
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
1617
use Symfony\Component\DependencyInjection\ContainerBuilder;
1718
use Symfony\Component\DependencyInjection\ContainerInterface;
1819
use Symfony\Component\DependencyInjection\Dumper\XmlDumper;
@@ -200,6 +201,19 @@ public function testDumpLoad()
200201
$this->assertStringEqualsFile(self::$fixturesPath.'/xml/services_dump_load.xml', $dumper->dump());
201202
}
202203

204+
public function testTaggedArgument()
205+
{
206+
$container = new ContainerBuilder();
207+
$container->register('foo', 'Foo')->addTag('foo_tag');
208+
$container->register('foo_tagged_iterator', 'Bar')
209+
->setPublic(true)
210+
->addArgument(new TaggedIteratorArgument('foo_tag', 'barfoo', 'foobar'))
211+
;
212+
213+
$dumper = new XmlDumper($container);
214+
$this->assertStringEqualsFile(self::$fixturesPath.'/xml/services_with_tagged_arguments.xml', $dumper->dump());
215+
}
216+
203217
public function testDumpAbstractServices()
204218
{
205219
$container = include self::$fixturesPath.'/containers/container_abstract.php';

src/Symfony/Component/DependencyInjection/Tests/Dumper/YamlDumperTest.php

+11
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use PHPUnit\Framework\TestCase;
1515
use Symfony\Component\Config\FileLocator;
16+
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
1617
use Symfony\Component\DependencyInjection\ContainerBuilder;
1718
use Symfony\Component\DependencyInjection\ContainerInterface;
1819
use Symfony\Component\DependencyInjection\Definition;
@@ -95,6 +96,16 @@ public function testInlineServices()
9596
$this->assertStringEqualsFile(self::$fixturesPath.'/yaml/services_inline.yml', $dumper->dump());
9697
}
9798

99+
public function testTaggedArgument()
100+
{
101+
$container = new ContainerBuilder();
102+
$container->register('foo_service', 'Foo')->addTag('foo');
103+
$container->register('foo_service_tagged', 'Bar')->addArgument(new TaggedIteratorArgument('foo', 'barfoo', 'foobar'));
104+
105+
$dumper = new YamlDumper($container);
106+
$this->assertStringEqualsFile(self::$fixturesPath.'/yaml/services_with_tagged_argument.yml', $dumper->dump());
107+
}
108+
98109
private function assertEqualYamlStructure($expected, $yaml, $message = '')
99110
{
100111
$parser = new Parser();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
namespace Symfony\Component\DependencyInjection\Tests\Fixtures;
4+
5+
class BarTagClass
6+
{
7+
public static function getDefaultFooName()
8+
{
9+
return 'bar_tag_class';
10+
}
11+
12+
public static function getFooBar()
13+
{
14+
return 'bar_tab_class_with_defaultmethod';
15+
}
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
namespace Symfony\Component\DependencyInjection\Tests\Fixtures;
4+
5+
class FooBarTaggedClass
6+
{
7+
private $param;
8+
9+
public function __construct($param = [])
10+
{
11+
$this->param = $param;
12+
}
13+
14+
public function getParam()
15+
{
16+
return $this->param;
17+
}
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
namespace Symfony\Component\DependencyInjection\Tests\Fixtures;
4+
5+
class FooTagClass
6+
{
7+
public static function getDefaultFooName()
8+
{
9+
return 'foo_tag_class';
10+
}
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
3+
<services>
4+
<service id="service_container" class="Symfony\Component\DependencyInjection\ContainerInterface" public="true" synthetic="true"/>
5+
<service id="foo" class="Foo">
6+
<tag name="foo_tag"/>
7+
</service>
8+
<service id="foo_tagged_iterator" class="Bar" public="true">
9+
<argument type="tagged" tag="foo_tag" index-by="barfoo" default-index-method="foobar"/>
10+
</service>
11+
<service id="Psr\Container\ContainerInterface" alias="service_container" public="false"/>
12+
<service id="Symfony\Component\DependencyInjection\ContainerInterface" alias="service_container" public="false"/>
13+
</services>
14+
</container>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
2+
services:
3+
service_container:
4+
class: Symfony\Component\DependencyInjection\ContainerInterface
5+
public: true
6+
synthetic: true
7+
foo_service:
8+
class: Foo
9+
tags:
10+
- { name: foo }
11+
foo_service_tagged:
12+
class: Bar
13+
arguments: [!tagged { tag: foo, index_by: barfoo, default_index_method: foobar }]
14+
Psr\Container\ContainerInterface:
15+
alias: service_container
16+
public: false
17+
Symfony\Component\DependencyInjection\ContainerInterface:
18+
alias: service_container
19+
public: false

src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php

+12
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use Symfony\Component\Config\Resource\GlobResource;
1919
use Symfony\Component\DependencyInjection\Argument\BoundArgument;
2020
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
21+
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
2122
use Symfony\Component\DependencyInjection\ContainerBuilder;
2223
use Symfony\Component\DependencyInjection\Dumper\PhpDumper;
2324
use Symfony\Component\DependencyInjection\Loader\IniFileLoader;
@@ -315,6 +316,17 @@ public function testParsesTags()
315316
}
316317
}
317318

319+
public function testParseTaggedArgumentsWithIndexBy()
320+
{
321+
$container = new ContainerBuilder();
322+
$loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml'));
323+
$loader->load('services_with_tagged_arguments.xml');
324+
325+
$this->assertCount(1, $container->getDefinition('foo')->getTag('foo_tag'));
326+
$this->assertCount(1, $container->getDefinition('foo_tagged_iterator')->getArguments());
327+
$this->assertEquals(new TaggedIteratorArgument('foo_tag', 'barfoo', 'foobar'), $container->getDefinition('foo_tagged_iterator')->getArgument(0));
328+
}
329+
318330
/**
319331
* @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException
320332
*/

src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php

+12
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use Symfony\Component\Config\Resource\GlobResource;
1919
use Symfony\Component\DependencyInjection\Argument\BoundArgument;
2020
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
21+
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
2122
use Symfony\Component\DependencyInjection\ContainerBuilder;
2223
use Symfony\Component\DependencyInjection\Loader\IniFileLoader;
2324
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
@@ -279,6 +280,17 @@ public function testTagWithoutNameThrowsException()
279280
}
280281
}
281282

283+
public function testTaggedArgumentsWithIndex()
284+
{
285+
$container = new ContainerBuilder();
286+
$loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml'));
287+
$loader->load('services_with_tagged_argument.yml');
288+
289+
$this->assertCount(1, $container->getDefinition('foo_service')->getTag('foo'));
290+
$this->assertCount(1, $container->getDefinition('foo_service_tagged')->getArguments());
291+
$this->assertEquals(new TaggedIteratorArgument('foo', 'barfoo', 'foobar'), $container->getDefinition('foo_service_tagged')->getArgument(0));
292+
}
293+
282294
public function testNameOnlyTagsAreAllowedAsString()
283295
{
284296
$container = new ContainerBuilder();

0 commit comments

Comments
 (0)