diff --git a/src/Symfony/Component/DependencyInjection/Loader/FileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/FileLoader.php index bb9dc214e6a50..def72ad142530 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/FileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/FileLoader.php @@ -59,11 +59,48 @@ public function registerClasses(Definition $prototype, $namespace, $resource) } $classes = $this->findClasses($namespace, $resource); + + $unusedArguments = array(); + foreach ($prototype->getArguments() as $key => $argument) { + if ('' === $key || '$' !== $key[0]) { + continue; + } + + $unusedArguments[$key] = true; + } + // prepare for deep cloning $prototype = serialize($prototype); - foreach ($classes as $class) { - $this->setDefinition($class, unserialize($prototype)); + foreach ($classes as $class => $reflectionClass) { + $parameters = array(); + if ($reflectionClass->hasMethod('__construct')) { + foreach ($reflectionClass->getMethod('__construct')->getParameters() as $parameter) { + $parameters['$'.$parameter->name] = true; + } + } + + $definition = unserialize($prototype); + + $arguments = array(); + foreach ($definition->getArguments() as $key => $argument) { + if ('' !== $key && '$' === $key[0]) { + if (!isset($parameters[$key])) { + continue; + } + + unset($unusedArguments[$key]); + } + + $arguments[$key] = $argument; + } + $definition->setArguments($arguments); + + $this->setDefinition($class, $definition); + } + + if ($unusedArguments) { + throw new InvalidArgumentException(sprintf('Unused named arguments in a prototype: "%s".', implode('", "', array_keys($unusedArguments)))); } } @@ -104,7 +141,7 @@ private function findClasses($namespace, $resource) continue; } if (!$r->isInterface() && !$r->isTrait()) { - $classes[] = $class; + $classes[$class] = $r; } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Prototype/Foo.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Prototype/Foo.php index 1e4f283c8f16e..5520c2fd1dbf4 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Prototype/Foo.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Prototype/Foo.php @@ -4,4 +4,7 @@ class Foo { + public function __construct($bar = null) + { + } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/prototype_named_args.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/prototype_named_args.yml new file mode 100644 index 0000000000000..005085b30b3bc --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/prototype_named_args.yml @@ -0,0 +1,5 @@ +services: + Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\: + resource: ../Prototype + arguments: + $bar: foo diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/prototype_unused_named_args.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/prototype_unused_named_args.yml new file mode 100644 index 0000000000000..6baa759d72fc1 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/prototype_unused_named_args.yml @@ -0,0 +1,6 @@ +services: + Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\: + resource: ../Prototype + arguments: + $invalid: foo + $invalid2: quz diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php index a30aa12c52712..ee04d03a8926b 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php @@ -24,7 +24,6 @@ use Symfony\Component\Config\Resource\DirectoryResource; use Symfony\Component\Config\Resource\FileResource; use Symfony\Component\DependencyInjection\Tests\Fixtures\CaseSensitiveClass; -use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype; use Symfony\Component\DependencyInjection\Tests\Fixtures\NamedArgumentsDummy; use Symfony\Component\ExpressionLanguage\Expression; @@ -450,6 +449,33 @@ public function testNamedArguments() $this->assertEquals(array(array('setApiKey', array('123'))), $container->getDefinition('another_one')->getMethodCalls()); } + public function testNamedArgumentsInPrototypes() + { + $container = new ContainerBuilder(); + $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); + $loader->load('prototype_named_args.yml'); + + $fooDefinition = $container->getDefinition('Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\Foo'); + $this->assertEquals(array('$bar' => 'foo'), $fooDefinition->getArguments()); + + $this->assertEmpty($container->getDefinition('Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\Sub\Bar')->getArguments()); + + $container->compile(); + + $this->assertEquals(array('foo'), $fooDefinition->getArguments()); + } + + /** + * @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException + * @expectedExceptionMessage Unused named arguments in a prototype: "$invalid", "$invalid2". + */ + public function testUnusedNamedArgumentsInPrototypes() + { + $container = new ContainerBuilder(); + $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); + $loader->load('prototype_unused_named_args.yml'); + } + public function testInstanceof() { $container = new ContainerBuilder();