diff --git a/src/Symfony/Component/DependencyInjection/Argument/AbstractArgument.php b/src/Symfony/Component/DependencyInjection/Argument/AbstractArgument.php new file mode 100644 index 0000000000..8eb6d5b424 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Argument/AbstractArgument.php @@ -0,0 +1,44 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DependencyInjection\Argument; + +/** + * Represents an abstract service argument, which have to be set by a compiler pass or a DI extension. + */ +final class AbstractArgument +{ + private $serviceId; + private $argKey; + private $text; + + public function __construct(string $serviceId, string $argKey, string $text = '') + { + $this->serviceId = $serviceId; + $this->argKey = $argKey; + $this->text = $text; + } + + public function getServiceId(): string + { + return $this->serviceId; + } + + public function getArgumentKey(): string + { + return $this->argKey; + } + + public function getText(): string + { + return $this->text; + } +} diff --git a/src/Symfony/Component/DependencyInjection/CHANGELOG.md b/src/Symfony/Component/DependencyInjection/CHANGELOG.md index b35c8808ae..0bacf3d561 100644 --- a/src/Symfony/Component/DependencyInjection/CHANGELOG.md +++ b/src/Symfony/Component/DependencyInjection/CHANGELOG.md @@ -6,6 +6,7 @@ CHANGELOG * added support to autowire public typed properties in php 7.4 * added support for defining method calls, a configurator, and property setters in `InlineServiceConfigurator` + * added possibility to define abstract service arguments 5.0.0 ----- diff --git a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php index 414dad611c..fbc11fa7ac 100644 --- a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php +++ b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php @@ -20,6 +20,7 @@ use Symfony\Component\Config\Resource\FileResource; use Symfony\Component\Config\Resource\GlobResource; use Symfony\Component\Config\Resource\ReflectionClassResource; use Symfony\Component\Config\Resource\ResourceInterface; +use Symfony\Component\DependencyInjection\Argument\AbstractArgument; use Symfony\Component\DependencyInjection\Argument\IteratorArgument; use Symfony\Component\DependencyInjection\Argument\RewindableGenerator; use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; @@ -1215,6 +1216,8 @@ class ContainerBuilder extends Container implements TaggedContainerInterface $value = $this->getParameter((string) $value); } elseif ($value instanceof Expression) { $value = $this->getExpressionLanguage()->evaluate($value, ['container' => $this]); + } elseif ($value instanceof AbstractArgument) { + throw new RuntimeException(sprintf('Argument "%s" of service "%s" is abstract%s, did you forget to define it?', $value->getArgumentKey(), $value->getServiceId(), $value->getText() ? ' ('.$value->getText().')' : '')); } return $value; diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php index 6f413881bc..b3763ae628 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php @@ -13,6 +13,7 @@ namespace Symfony\Component\DependencyInjection\Dumper; use Composer\Autoload\ClassLoader; use Symfony\Component\Debug\DebugClassLoader as LegacyDebugClassLoader; +use Symfony\Component\DependencyInjection\Argument\AbstractArgument; use Symfony\Component\DependencyInjection\Argument\ArgumentInterface; use Symfony\Component\DependencyInjection\Argument\IteratorArgument; use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; @@ -1739,6 +1740,8 @@ EOF; return $code; } + } elseif ($value instanceof AbstractArgument) { + throw new RuntimeException(sprintf('Argument "%s" of service "%s" is abstract%s, did you forget to define it?', $value->getArgumentKey(), $value->getServiceId(), $value->getText() ? ' ('.$value->getText().')' : '')); } elseif (\is_object($value) || \is_resource($value)) { throw new RuntimeException('Unable to dump a service container if a parameter is an object or a resource.'); } diff --git a/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php index fb5d827acd..6f7d918d26 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php @@ -12,6 +12,7 @@ namespace Symfony\Component\DependencyInjection\Dumper; use Symfony\Component\DependencyInjection\Alias; +use Symfony\Component\DependencyInjection\Argument\AbstractArgument; use Symfony\Component\DependencyInjection\Argument\IteratorArgument; use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument; @@ -312,6 +313,14 @@ class XmlDumper extends Dumper $element->setAttribute('type', 'binary'); $text = $this->document->createTextNode(self::phpToXml(base64_encode($value))); $element->appendChild($text); + } elseif ($value instanceof AbstractArgument) { + $argKey = $value->getArgumentKey(); + if (!is_numeric($argKey)) { + $element->setAttribute('key', $argKey); + } + $element->setAttribute('type', 'abstract'); + $text = $this->document->createTextNode(self::phpToXml($value->getText())); + $element->appendChild($text); } else { if (\in_array($value, ['null', 'true', 'false'], true)) { $element->setAttribute('type', 'string'); diff --git a/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php index ccb68ee8f1..bba092c64e 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php @@ -12,6 +12,7 @@ namespace Symfony\Component\DependencyInjection\Dumper; use Symfony\Component\DependencyInjection\Alias; +use Symfony\Component\DependencyInjection\Argument\AbstractArgument; use Symfony\Component\DependencyInjection\Argument\ArgumentInterface; use Symfony\Component\DependencyInjection\Argument\IteratorArgument; use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; @@ -284,6 +285,8 @@ class YamlDumper extends Dumper return $this->getExpressionCall((string) $value); } elseif ($value instanceof Definition) { return new TaggedValue('service', (new Parser())->parse("_:\n".$this->addService('_', $value), Yaml::PARSE_CUSTOM_TAGS)['_']['_']); + } elseif ($value instanceof AbstractArgument) { + return new TaggedValue('abstract', $value->getText()); } elseif (\is_object($value) || \is_resource($value)) { throw new RuntimeException('Unable to dump a service container if a parameter is an object or a resource.'); } diff --git a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php index 82e61b6335..6cad945304 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php @@ -13,6 +13,7 @@ namespace Symfony\Component\DependencyInjection\Loader; use Symfony\Component\Config\Util\XmlUtils; use Symfony\Component\DependencyInjection\Alias; +use Symfony\Component\DependencyInjection\Argument\AbstractArgument; use Symfony\Component\DependencyInjection\Argument\BoundArgument; use Symfony\Component\DependencyInjection\Argument\IteratorArgument; use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument; @@ -537,6 +538,10 @@ class XmlFileLoader extends FileLoader } $arguments[$key] = $value; break; + case 'abstract': + $serviceId = $node->getAttribute('id'); + $arguments[$key] = new AbstractArgument($serviceId, (string) $key, $arg->nodeValue); + break; case 'string': $arguments[$key] = $arg->nodeValue; break; diff --git a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php index cb17e5743d..1722f7ac73 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php @@ -12,6 +12,7 @@ namespace Symfony\Component\DependencyInjection\Loader; use Symfony\Component\DependencyInjection\Alias; +use Symfony\Component\DependencyInjection\Argument\AbstractArgument; use Symfony\Component\DependencyInjection\Argument\ArgumentInterface; use Symfony\Component\DependencyInjection\Argument\BoundArgument; use Symfony\Component\DependencyInjection\Argument\IteratorArgument; @@ -446,7 +447,7 @@ class YamlFileLoader extends FileLoader } if (isset($service['arguments'])) { - $definition->setArguments($this->resolveServices($service['arguments'], $file)); + $definition->setArguments($this->resolveServices($service['arguments'], $file, false, $id)); } if (isset($service['properties'])) { @@ -722,7 +723,7 @@ class YamlFileLoader extends FileLoader * * @return array|string|Reference|ArgumentInterface */ - private function resolveServices($value, string $file, bool $isParameter = false) + private function resolveServices($value, string $file, bool $isParameter = false, string $serviceId = '', string $argKey = '') { if ($value instanceof TaggedValue) { $argument = $value->getValue(); @@ -795,13 +796,16 @@ class YamlFileLoader extends FileLoader return new Reference($id); } + if ('abstract' === $value->getTag()) { + return new AbstractArgument($serviceId, $argKey, $value->getValue()); + } throw new InvalidArgumentException(sprintf('Unsupported tag "!%s".', $value->getTag())); } if (\is_array($value)) { foreach ($value as $k => $v) { - $value[$k] = $this->resolveServices($v, $file, $isParameter); + $value[$k] = $this->resolveServices($v, $file, $isParameter, $serviceId, $k); } } elseif (\is_string($value) && 0 === strpos($value, '@=')) { if (!class_exists(Expression::class)) { 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 2f745c3326..d2c81bcf31 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 @@ -260,6 +260,7 @@ + diff --git a/src/Symfony/Component/DependencyInjection/Tests/Argument/AbstractArgumentTest.php b/src/Symfony/Component/DependencyInjection/Tests/Argument/AbstractArgumentTest.php new file mode 100644 index 0000000000..91b1a5665b --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Argument/AbstractArgumentTest.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DependencyInjection\Tests\Argument; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\DependencyInjection\Argument\AbstractArgument; + +class AbstractArgumentTest extends TestCase +{ + public function testAbstractArgumentGetters() + { + $argument = new AbstractArgument('foo', '$bar', 'should be defined by Pass'); + $this->assertSame('foo', $argument->getServiceId()); + $this->assertSame('$bar', $argument->getArgumentKey()); + $this->assertSame('should be defined by Pass', $argument->getText()); + } +} diff --git a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php index c570958cad..5763b1d4f5 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php @@ -22,6 +22,7 @@ use Symfony\Component\Config\Resource\DirectoryResource; use Symfony\Component\Config\Resource\FileResource; use Symfony\Component\Config\Resource\ResourceInterface; use Symfony\Component\DependencyInjection\Alias; +use Symfony\Component\DependencyInjection\Argument\AbstractArgument; use Symfony\Component\DependencyInjection\Argument\IteratorArgument; use Symfony\Component\DependencyInjection\Argument\RewindableGenerator; use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; @@ -41,6 +42,7 @@ use Symfony\Component\DependencyInjection\Tests\Compiler\Foo; use Symfony\Component\DependencyInjection\Tests\Compiler\Wither; use Symfony\Component\DependencyInjection\Tests\Fixtures\CaseSensitiveClass; use Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition; +use Symfony\Component\DependencyInjection\Tests\Fixtures\FooWithAbstractArgument; use Symfony\Component\DependencyInjection\Tests\Fixtures\ScalarFactory; use Symfony\Component\DependencyInjection\Tests\Fixtures\SimilarArgumentsDummy; use Symfony\Component\DependencyInjection\TypedReference; @@ -542,6 +544,18 @@ class ContainerBuilderTest extends TestCase $this->assertEquals('foobar', $builder->get('foo')->arguments['foo']); } + public function testCreateServiceWithAbstractArgument() + { + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('Argument "$baz" of service "foo" is abstract (should be defined by Pass), did you forget to define it?'); + + $builder = new ContainerBuilder(); + $builder->register('foo', FooWithAbstractArgument::class) + ->addArgument(new AbstractArgument('foo', '$baz', 'should be defined by Pass')); + + $builder->get('foo'); + } + public function testResolveServices() { $builder = new ContainerBuilder(); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php index 17f67ed099..0fbd9f08ea 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php @@ -15,6 +15,7 @@ use PHPUnit\Framework\TestCase; use Psr\Container\ContainerInterface; use Symfony\Bridge\ProxyManager\LazyProxy\PhpDumper\ProxyDumper; use Symfony\Component\Config\FileLocator; +use Symfony\Component\DependencyInjection\Argument\AbstractArgument; use Symfony\Component\DependencyInjection\Argument\IteratorArgument; use Symfony\Component\DependencyInjection\Argument\RewindableGenerator; use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; @@ -33,6 +34,7 @@ use Symfony\Component\DependencyInjection\ServiceLocator; use Symfony\Component\DependencyInjection\Tests\Compiler\Foo; use Symfony\Component\DependencyInjection\Tests\Compiler\Wither; use Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition; +use Symfony\Component\DependencyInjection\Tests\Fixtures\FooWithAbstractArgument; use Symfony\Component\DependencyInjection\Tests\Fixtures\ScalarFactory; use Symfony\Component\DependencyInjection\Tests\Fixtures\StubbedTranslator; use Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber; @@ -1363,6 +1365,24 @@ class PhpDumperTest extends TestCase $this->assertInstanceOf(\stdClass::class, $container->get('deprecated1')); $this->assertInstanceOf(\stdClass::class, $container->get('deprecated2')); } + + public function testDumpServiceWithAbstractArgument() + { + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('Argument "$baz" of service "Symfony\Component\DependencyInjection\Tests\Fixtures\FooWithAbstractArgument" is abstract (should be defined by Pass), did you forget to define it?'); + + $container = new ContainerBuilder(); + + $container->register(FooWithAbstractArgument::class, FooWithAbstractArgument::class) + ->setArgument('$baz', new AbstractArgument(FooWithAbstractArgument::class, '$baz', 'should be defined by Pass')) + ->setArgument('$bar', 'test') + ->setPublic(true); + + $container->compile(); + + $dumper = new PhpDumper($container); + $dumper->dump(); + } } class Rot13EnvVarProcessor implements EnvVarProcessorInterface diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/XmlDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/XmlDumperTest.php index 4472782820..ced0915761 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/XmlDumperTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/XmlDumperTest.php @@ -13,6 +13,7 @@ namespace Symfony\Component\DependencyInjection\Tests\Dumper; use PHPUnit\Framework\TestCase; use Symfony\Component\Config\FileLocator; +use Symfony\Component\DependencyInjection\Argument\AbstractArgument; use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument; use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -20,6 +21,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\Dumper\XmlDumper; use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\DependencyInjection\Tests\Fixtures\FooWithAbstractArgument; class XmlDumperTest extends TestCase { @@ -237,4 +239,15 @@ class XmlDumperTest extends TestCase $this->assertEquals(file_get_contents(self::$fixturesPath.'/xml/services_abstract.xml'), $dumper->dump()); } + + public function testDumpServiceWithAbstractArgument() + { + $container = new ContainerBuilder(); + $container->register(FooWithAbstractArgument::class, FooWithAbstractArgument::class) + ->setArgument('$baz', new AbstractArgument(FooWithAbstractArgument::class, '$baz', 'should be defined by Pass')) + ->setArgument('$bar', 'test'); + + $dumper = new XmlDumper($container); + $this->assertStringEqualsFile(self::$fixturesPath.'/xml/services_with_abstract_argument.xml', $dumper->dump()); + } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/YamlDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/YamlDumperTest.php index 7a83b2e6a1..d7896ae436 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/YamlDumperTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/YamlDumperTest.php @@ -13,6 +13,7 @@ namespace Symfony\Component\DependencyInjection\Tests\Dumper; use PHPUnit\Framework\TestCase; use Symfony\Component\Config\FileLocator; +use Symfony\Component\DependencyInjection\Argument\AbstractArgument; use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument; use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -21,6 +22,7 @@ use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Dumper\YamlDumper; use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\DependencyInjection\Tests\Fixtures\FooWithAbstractArgument; use Symfony\Component\Yaml\Parser; use Symfony\Component\Yaml\Yaml; @@ -117,6 +119,17 @@ class YamlDumperTest extends TestCase $this->assertStringEqualsFile(self::$fixturesPath.'/yaml/services_with_tagged_argument.yml', $dumper->dump()); } + public function testDumpServiceWithAbstractArgument() + { + $container = new ContainerBuilder(); + $container->register(FooWithAbstractArgument::class, FooWithAbstractArgument::class) + ->setArgument('$baz', new AbstractArgument(FooWithAbstractArgument::class, '$baz', 'should be defined by Pass')) + ->setArgument('$bar', 'test'); + + $dumper = new YamlDumper($container); + $this->assertStringEqualsFile(self::$fixturesPath.'/yaml/services_with_abstract_argument.yml', $dumper->dump()); + } + private function assertEqualYamlStructure(string $expected, string $yaml, string $message = '') { $parser = new Parser(); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/FooWithAbstractArgument.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/FooWithAbstractArgument.php new file mode 100644 index 0000000000..b76374127f --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/FooWithAbstractArgument.php @@ -0,0 +1,18 @@ +baz = $baz; + $this->bar = $bar; + } +} diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/service_with_abstract_argument.xml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/service_with_abstract_argument.xml new file mode 100644 index 0000000000..c7ba195076 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/service_with_abstract_argument.xml @@ -0,0 +1,9 @@ + + + + + should be defined by FooCompilerPass + test + + + diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_with_abstract_argument.xml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_with_abstract_argument.xml new file mode 100644 index 0000000000..8a05525f55 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_with_abstract_argument.xml @@ -0,0 +1,12 @@ + + + + + + should be defined by Pass + test + + + + + diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_abstract_argument.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_abstract_argument.yml new file mode 100644 index 0000000000..02889228c0 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_abstract_argument.yml @@ -0,0 +1,15 @@ + +services: + service_container: + class: Symfony\Component\DependencyInjection\ContainerInterface + public: true + synthetic: true + Symfony\Component\DependencyInjection\Tests\Fixtures\FooWithAbstractArgument: + class: Symfony\Component\DependencyInjection\Tests\Fixtures\FooWithAbstractArgument + arguments: { $baz: !abstract 'should be defined by Pass', $bar: test } + Psr\Container\ContainerInterface: + alias: service_container + public: false + Symfony\Component\DependencyInjection\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 14ba4c7f6e..55831540aa 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php @@ -16,6 +16,7 @@ use Symfony\Component\Config\FileLocator; use Symfony\Component\Config\Loader\LoaderResolver; use Symfony\Component\Config\Resource\FileResource; use Symfony\Component\Config\Resource\GlobResource; +use Symfony\Component\DependencyInjection\Argument\AbstractArgument; use Symfony\Component\DependencyInjection\Argument\BoundArgument; use Symfony\Component\DependencyInjection\Argument\IteratorArgument; use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument; @@ -31,6 +32,7 @@ use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\Tests\Fixtures\Bar; use Symfony\Component\DependencyInjection\Tests\Fixtures\BarInterface; use Symfony\Component\DependencyInjection\Tests\Fixtures\CaseSensitiveClass; +use Symfony\Component\DependencyInjection\Tests\Fixtures\FooWithAbstractArgument; use Symfony\Component\DependencyInjection\Tests\Fixtures\NamedArgumentsDummy; use Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype; use Symfony\Component\ExpressionLanguage\Expression; @@ -992,4 +994,15 @@ class XmlFileLoaderTest extends TestCase $this->assertSame(Prototype\SinglyImplementedInterface\Adapter\Adapter::class, (string) $alias); } + + public function testLoadServiceWithAbstractArgument() + { + $container = new ContainerBuilder(); + $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); + $loader->load('service_with_abstract_argument.xml'); + + $this->assertTrue($container->hasDefinition(FooWithAbstractArgument::class)); + $arguments = $container->getDefinition(FooWithAbstractArgument::class)->getArguments(); + $this->assertInstanceOf(AbstractArgument::class, $arguments['$baz']); + } }