Skip to content

Commit 024e929

Browse files
Merge branch '4.4' into 5.2
* 4.4: [DependencyInjection] fix dumping service-closure-arguments
2 parents 3439216 + c1d4b65 commit 024e929

File tree

11 files changed

+107
-4
lines changed

11 files changed

+107
-4
lines changed

Dumper/XmlDumper.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -275,9 +275,6 @@ private function convertParameters(array $parameters, string $type, \DOMElement
275275
$element->setAttribute($keyAttribute, $key);
276276
}
277277

278-
if ($value instanceof ServiceClosureArgument) {
279-
$value = $value->getValues()[0];
280-
}
281278
if (\is_array($tag = $value)) {
282279
$element->setAttribute('type', 'collection');
283280
$this->convertParameters($value, $type, $element, 'key');
@@ -301,8 +298,12 @@ private function convertParameters(array $parameters, string $type, \DOMElement
301298
} elseif ($value instanceof ServiceLocatorArgument) {
302299
$element->setAttribute('type', 'service_locator');
303300
$this->convertParameters($value->getValues(), $type, $element, 'key');
304-
} elseif ($value instanceof Reference) {
301+
} elseif ($value instanceof Reference || $value instanceof ServiceClosureArgument) {
305302
$element->setAttribute('type', 'service');
303+
if ($value instanceof ServiceClosureArgument) {
304+
$element->setAttribute('type', 'service_closure');
305+
$value = $value->getValues()[0];
306+
}
306307
$element->setAttribute('id', (string) $value);
307308
$behavior = $value->getInvalidBehavior();
308309
if (ContainerInterface::NULL_ON_INVALID_REFERENCE == $behavior) {

Dumper/YamlDumper.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,8 @@ private function dumpValue($value)
254254
{
255255
if ($value instanceof ServiceClosureArgument) {
256256
$value = $value->getValues()[0];
257+
258+
return new TaggedValue('service_closure', $this->getServiceCall((string) $value, $value));
257259
}
258260
if ($value instanceof ArgumentInterface) {
259261
$tag = $value;

Loader/XmlFileLoader.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use Symfony\Component\DependencyInjection\Argument\AbstractArgument;
1717
use Symfony\Component\DependencyInjection\Argument\BoundArgument;
1818
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
19+
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
1920
use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument;
2021
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
2122
use Symfony\Component\DependencyInjection\ChildDefinition;
@@ -494,6 +495,13 @@ private function getArgumentsAsPhp(\DOMElement $node, string $name, string $file
494495
throw new InvalidArgumentException(sprintf('Tag "<%s>" with type="iterator" only accepts collections of type="service" references in "%s".', $name, $file));
495496
}
496497
break;
498+
case 'service_closure':
499+
if ('' === $arg->getAttribute('id')) {
500+
throw new InvalidArgumentException(sprintf('Tag "<%s>" with type="service_closure" has no or empty "id" attribute in "%s".', $name, $file));
501+
}
502+
503+
$arguments[$key] = new ServiceClosureArgument(new Reference($arg->getAttribute('id'), $invalidBehavior));
504+
break;
497505
case 'service_locator':
498506
$arg = $this->getArgumentsAsPhp($arg, $name, $file);
499507
try {

Loader/YamlFileLoader.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
1717
use Symfony\Component\DependencyInjection\Argument\BoundArgument;
1818
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
19+
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
1920
use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument;
2021
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
2122
use Symfony\Component\DependencyInjection\ChildDefinition;
@@ -797,6 +798,15 @@ private function resolveServices($value, string $file, bool $isParameter = false
797798
throw new InvalidArgumentException(sprintf('"!iterator" tag only accepts arrays of "@service" references in "%s".', $file));
798799
}
799800
}
801+
if ('service_closure' === $value->getTag()) {
802+
$argument = $this->resolveServices($argument, $file, $isParameter);
803+
804+
if (!$argument instanceof Reference) {
805+
throw new InvalidArgumentException(sprintf('"!service_closure" tag only accepts service references in "%s".', $file));
806+
}
807+
808+
return new ServiceClosureArgument($argument);
809+
}
800810
if ('service_locator' === $value->getTag()) {
801811
if (!\is_array($argument)) {
802812
throw new InvalidArgumentException(sprintf('"!service_locator" tag only accepts maps in "%s".', $file));

Loader/schema/dic/services/services-1.0.xsd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,7 @@
291291
<xsd:enumeration value="constant" />
292292
<xsd:enumeration value="binary" />
293293
<xsd:enumeration value="iterator" />
294+
<xsd:enumeration value="service_closure" />
294295
<xsd:enumeration value="service_locator" />
295296
<!-- "tagged" is an alias of "tagged_iterator", using "tagged_iterator" is preferred. -->
296297
<xsd:enumeration value="tagged" />

Tests/Dumper/XmlDumperTest.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use PHPUnit\Framework\TestCase;
1515
use Symfony\Component\Config\FileLocator;
1616
use Symfony\Component\DependencyInjection\Argument\AbstractArgument;
17+
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
1718
use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument;
1819
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
1920
use Symfony\Component\DependencyInjection\ContainerBuilder;
@@ -252,6 +253,17 @@ public function testTaggedArguments()
252253
$this->assertStringEqualsFile(self::$fixturesPath.'/xml/services_with_tagged_arguments.xml', $dumper->dump());
253254
}
254255

256+
public function testServiceClosure()
257+
{
258+
$container = new ContainerBuilder();
259+
$container->register('foo', 'Foo')
260+
->addArgument(new ServiceClosureArgument(new Reference('bar', ContainerInterface::IGNORE_ON_INVALID_REFERENCE)))
261+
;
262+
263+
$dumper = new XmlDumper($container);
264+
$this->assertStringEqualsFile(self::$fixturesPath.'/xml/services_with_service_closure.xml', $dumper->dump());
265+
}
266+
255267
public function testDumpAbstractServices()
256268
{
257269
$container = include self::$fixturesPath.'/containers/container_abstract.php';

Tests/Dumper/YamlDumperTest.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use PHPUnit\Framework\TestCase;
1515
use Symfony\Component\Config\FileLocator;
1616
use Symfony\Component\DependencyInjection\Argument\AbstractArgument;
17+
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
1718
use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument;
1819
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
1920
use Symfony\Component\DependencyInjection\ContainerBuilder;
@@ -119,6 +120,17 @@ public function testTaggedArguments()
119120
$this->assertStringEqualsFile(self::$fixturesPath.'/yaml/services_with_tagged_argument.yml', $dumper->dump());
120121
}
121122

123+
public function testServiceClosure()
124+
{
125+
$container = new ContainerBuilder();
126+
$container->register('foo', 'Foo')
127+
->addArgument(new ServiceClosureArgument(new Reference('bar', ContainerInterface::IGNORE_ON_INVALID_REFERENCE)))
128+
;
129+
130+
$dumper = new YamlDumper($container);
131+
$this->assertStringEqualsFile(self::$fixturesPath.'/yaml/services_with_service_closure.yml', $dumper->dump());
132+
}
133+
122134
public function testDumpServiceWithAbstractArgument()
123135
{
124136
$container = new ContainerBuilder();
@@ -130,6 +142,7 @@ public function testDumpServiceWithAbstractArgument()
130142
$this->assertStringEqualsFile(self::$fixturesPath.'/yaml/services_with_abstract_argument.yml', $dumper->dump());
131143
}
132144

145+
133146
private function assertEqualYamlStructure(string $expected, string $yaml, string $message = '')
134147
{
135148
$parser = new Parser();
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
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 https://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+
<argument type="service_closure" id="bar" on-invalid="ignore"/>
7+
</service>
8+
<service id="Psr\Container\ContainerInterface" alias="service_container">
9+
<deprecated package="symfony/dependency-injection" version="5.1">The "%alias_id%" autowiring alias is deprecated. Define it explicitly in your app if you want to keep using it.</deprecated>
10+
</service>
11+
<service id="Symfony\Component\DependencyInjection\ContainerInterface" alias="service_container">
12+
<deprecated package="symfony/dependency-injection" version="5.1">The "%alias_id%" autowiring alias is deprecated. Define it explicitly in your app if you want to keep using it.</deprecated>
13+
</service>
14+
</services>
15+
</container>
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
2+
services:
3+
service_container:
4+
class: Symfony\Component\DependencyInjection\ContainerInterface
5+
public: true
6+
synthetic: true
7+
foo:
8+
class: Foo
9+
arguments: [!service_closure '@?bar']
10+
Psr\Container\ContainerInterface:
11+
alias: service_container
12+
deprecated:
13+
package: symfony/dependency-injection
14+
version: 5.1
15+
message: The "%alias_id%" autowiring alias is deprecated. Define it explicitly in your app if you want to keep using it.
16+
Symfony\Component\DependencyInjection\ContainerInterface:
17+
alias: service_container
18+
deprecated:
19+
package: symfony/dependency-injection
20+
version: 5.1
21+
message: The "%alias_id%" autowiring alias is deprecated. Define it explicitly in your app if you want to keep using it.

Tests/Loader/XmlFileLoaderTest.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
use Symfony\Component\DependencyInjection\Argument\AbstractArgument;
2424
use Symfony\Component\DependencyInjection\Argument\BoundArgument;
2525
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
26+
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
2627
use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument;
2728
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
2829
use Symfony\Component\DependencyInjection\Compiler\ResolveBindingsPass;
@@ -381,6 +382,15 @@ public function testParseTaggedArgumentsWithIndexBy()
381382
$this->assertEquals(new ServiceLocatorArgument($taggedIterator), $container->getDefinition('foo_tagged_locator')->getArgument(0));
382383
}
383384

385+
public function testParseServiceClosure()
386+
{
387+
$container = new ContainerBuilder();
388+
$loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml'));
389+
$loader->load('services_with_service_closure.xml');
390+
391+
$this->assertEquals(new ServiceClosureArgument(new Reference('bar', ContainerInterface::IGNORE_ON_INVALID_REFERENCE)), $container->getDefinition('foo')->getArgument(0));
392+
}
393+
384394
public function testParseTagsWithoutNameThrowsException()
385395
{
386396
$this->expectException(InvalidArgumentException::class);

0 commit comments

Comments
 (0)