From 9828da296f6f2f45a741fffc8acd28e85f14a0e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Mon, 24 Aug 2015 03:36:41 +0200 Subject: [PATCH 01/19] [DependencyInjection] Add autowiring capabilities --- .../Compiler/AutowiringPass.php | 233 +++++++++++++++++ .../Compiler/PassConfig.php | 1 + .../DependencyInjection/Definition.php | 68 +++++ .../Loader/XmlFileLoader.php | 4 + .../Loader/YamlFileLoader.php | 14 + .../schema/dic/services/services-1.0.xsd | 1 + .../Tests/Compiler/AutowiringPassTest.php | 239 ++++++++++++++++++ .../Tests/ContainerBuilderTest.php | 23 ++ .../Tests/DefinitionTest.php | 13 + .../Tests/Fixtures/xml/services22.xml | 9 + .../Tests/Fixtures/yaml/bad_types1.yml | 5 + .../Tests/Fixtures/yaml/bad_types2.yml | 5 + .../Tests/Fixtures/yaml/services22.yml | 4 + .../Tests/Loader/XmlFileLoaderTest.php | 9 + .../Tests/Loader/YamlFileLoaderTest.php | 27 ++ 15 files changed, 655 insertions(+) create mode 100644 src/Symfony/Component/DependencyInjection/Compiler/AutowiringPass.php create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowiringPassTest.php create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services22.xml create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/bad_types1.yml create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/bad_types2.yml create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services22.yml diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AutowiringPass.php b/src/Symfony/Component/DependencyInjection/Compiler/AutowiringPass.php new file mode 100644 index 0000000000000..bae46b85ac88c --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Compiler/AutowiringPass.php @@ -0,0 +1,233 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DependencyInjection\Compiler; + +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Definition; +use Symfony\Component\DependencyInjection\Exception\RuntimeException; +use Symfony\Component\DependencyInjection\Reference; + +/** + * Guesses constructor arguments of services definitions and try to instantiate services if necessary. + * + * @author Kévin Dunglas + */ +class AutowiringPass implements CompilerPassInterface +{ + private $container; + private $definitions; + private $reflectionClassesToId = array(); + private $definedTypes = array(); + private $typesToId; + private $notGuessableTypesToId = array(); + + /** + * {@inheritdoc} + */ + public function process(ContainerBuilder $container) + { + $this->container = $container; + $this->definitions = $container->getDefinitions(); + foreach ($this->definitions as $id => $definition) { + $this->completeDefinition($id, $definition, $container); + } + } + + /** + * Wires the given definition. + * + * @param string $id + * @param Definition $definition + * + * @throws RuntimeException + */ + private function completeDefinition($id, Definition $definition) + { + if (!($reflectionClass = $this->getReflectionClass($id, $definition))) { + return; + } + + if (!($constructor = $reflectionClass->getConstructor())) { + return; + } + + $arguments = $definition->getArguments(); + foreach ($constructor->getParameters() as $index => $parameter) { + if (!($typeHint = $parameter->getClass()) || $parameter->isOptional()) { + continue; + } + + $argumentExist = array_key_exists($index, $arguments); + if ($argumentExist && '' !== $arguments[$index]) { + continue; + } + + if (null === $this->typesToId) { + $this->populateAvailableTypes(); + } + + if (isset($this->typesToId[$typeHint->name])) { + $reference = new Reference($this->typesToId[$typeHint->name]); + } else { + $reference = $this->createAutowiredDefinition($typeHint); + } + + if ($argumentExist) { + $definition->replaceArgument($index, $reference); + } else { + $definition->addArgument($reference); + } + } + } + + /** + * Populates the list of available types. + */ + private function populateAvailableTypes() + { + $this->typesToId = array(); + + foreach ($this->definitions as $id => $definition) { + $this->populateAvailableType($id, $definition); + } + } + + /** + * Populates the of available types for a given definition. + * + * @param string $id + * @param Definition $definition + */ + private function populateAvailableType($id, Definition $definition) { + if (!($class = $definition->getClass())) { + return; + } + + foreach ($definition->getTypes() as $type) { + $this->definedTypes[$type] = true; + $this->typesToId[$type] = $id; + } + + if ($reflectionClass = $this->getReflectionClass($id, $definition)) { + $this->extractInterfaces($id, $reflectionClass); + $this->extractAncestors($id, $reflectionClass); + } + } + + /** + * Extracts the list of all interfaces implemented by a class. + * + * @param string $id + * @param \ReflectionClass $reflectionClass + */ + private function extractInterfaces($id, \ReflectionClass $reflectionClass) + { + foreach ($reflectionClass->getInterfaces() as $interfaceName => $reflectionInterface) { + $this->set($interfaceName, $id); + + $this->extractInterfaces($id, $reflectionInterface); + } + } + + /** + * Extracts all inherited types of a class. + * + * @param string $id + * @param \ReflectionClass $reflectionClass + */ + private function extractAncestors($id, \ReflectionClass $reflectionClass) + { + $this->set($reflectionClass->name, $id); + + if ($reflectionParentClass = $reflectionClass->getParentClass()) { + $this->extractAncestors($id, $reflectionParentClass); + } + } + + /** + * Associates if applicable a type and a service id or a class. + * + * @param string $type + * @param string $value A service id or a class name depending of the value of $class + */ + private function set($type, $value) + { + if (isset($this->definedTypes[$type]) || isset($this->notGuessableTypesToId[$type])) { + return; + } + + if (isset($this->typesToId[$type])) { + if ($this->typesToId[$type] === $value) { + return; + } + + unset($this->typesToId[$type]); + + $this->notGuessableTypesToId[$type] = true; + return; + } + + $this->typesToId[$type] = $value; + } + + /** + * Registers a definition for the type if possible or throws an exception. + * + * @param \ReflectionClass $typeHint + * + * @return Reference A reference to the registered definition + * + * @throws RuntimeException + */ + private function createAutowiredDefinition(\ReflectionClass $typeHint) + { + if (!$typeHint->isInstantiable()) { + throw new RuntimeException(sprintf('Unable to autowire type "%s".', $typeHint->name)); + } + + $argumentId = sprintf('autowired.%s', $typeHint->name); + + $argumentDefinition = $this->container->register($argumentId, $typeHint->name); + $argumentDefinition->setPublic(false); + + $this->definitions = $this->container->getDefinitions(); + $this->populateAvailableType($argumentId, $argumentDefinition); + $this->completeDefinition($argumentId, $argumentDefinition); + + return new Reference($argumentId); + } + + /** + * Retrieves the reflection class associated with the given service. + * + * @param string $id + * @param Definition $definition + * + * @return \ReflectionClass|null + */ + private function getReflectionClass($id, Definition $definition) + { + if (isset($this->reflectionClassesToId[$id])) { + return $this->reflectionClassesToId[$id]; + } + + if (!$class = $definition->getClass()) { + return; + } + + try { + return $this->reflectionClassesToId[$id] = new \ReflectionClass($class); + } catch (\ReflectionException $e) { + // Skip invalid classes definitions to keep BC + } + } +} diff --git a/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php b/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php index 2849dfe129a78..e89a00bb4d19e 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php @@ -51,6 +51,7 @@ public function __construct() new ResolveReferencesToAliasesPass(), new ResolveInvalidReferencesPass(), new AnalyzeServiceReferencesPass(true), + new AutowiringPass(), new CheckCircularReferencesPass(), new CheckReferenceValidityPass(), ); diff --git a/src/Symfony/Component/DependencyInjection/Definition.php b/src/Symfony/Component/DependencyInjection/Definition.php index 9ce81e3a12cfa..0bcd11b0263c7 100644 --- a/src/Symfony/Component/DependencyInjection/Definition.php +++ b/src/Symfony/Component/DependencyInjection/Definition.php @@ -41,6 +41,7 @@ class Definition private $synchronized = false; private $lazy = false; private $decoratedService; + private $types = array(); protected $arguments; @@ -818,4 +819,71 @@ public function getConfigurator() { return $this->configurator; } + + /** + * Sets types that will default to this definition. + * + * @param string[] $types + * + * @return Definition The current instance + */ + public function setTypes(array $types) + { + $this->types = array(); + + foreach ($types as $type) { + $this->types[$type] = true; + } + + return $this; + } + + /** + * Gets types that will default to this definition. + * + * @return string[] + */ + public function getTypes() + { + return array_keys($this->types); + } + + /** + * Adds a type that will default to this definition. + * + * @param string $type + * + * @return Definition The current instance + */ + public function addType($type) + { + $this->types[$type] = true; + + return $this; + } + + /** + * Removes a type. + * + * @param string $type + * + * @return Definition The current instance + */ + public function removeType($type) + { + unset($this->types[$type]); + + return $this; + } + + /** + * Will this definition default for the given type? + * + * @param string $type + * + * @return bool + */ + public function hasType($type) { + return isset($this->types[$type]); + } } diff --git a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php index 8a0e4ac24a65a..fa2c3f9234f6b 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php @@ -247,6 +247,10 @@ private function parseDefinition(\DOMElement $service, $file) $definition->addTag($tag->getAttribute('name'), $parameters); } + foreach ($this->getChildren($service, 'type') as $type) { + $definition->addType($type->textContent); + } + if ($value = $service->getAttribute('decorates')) { $renameId = $service->hasAttribute('decoration-inner-name') ? $service->getAttribute('decoration-inner-name') : null; $priority = $service->hasAttribute('decoration-priority') ? $service->getAttribute('decoration-priority') : 0; diff --git a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php index 19191a760c6cd..508c65144b7c6 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php @@ -299,6 +299,20 @@ private function parseDefinition($id, $service, $file) $definition->setDecoratedService($service['decorates'], $renameId, $priority); } + if (isset($service['types'])) { + if (!is_array($service['types'])) { + throw new InvalidArgumentException(sprintf('Parameter "types" must be an array for service "%s" in %s. Check your YAML syntax.', $id, $file)); + } + + foreach ($service['types'] as $type) { + if (!is_string($type)) { + throw new InvalidArgumentException(sprintf('A "types" attribute must be of type string for service "%s" in %s. Check your YAML syntax.', $id, $file)); + } + + $definition->addType($type); + } + } + $this->container->setDefinition($id, $definition); } 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 cbaa3606f7a04..1bf4eb5bc0859 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 @@ -85,6 +85,7 @@ + diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowiringPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowiringPassTest.php new file mode 100644 index 0000000000000..f656cc3526674 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowiringPassTest.php @@ -0,0 +1,239 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DependencyInjection\Tests\Compiler; + +use Symfony\Component\DependencyInjection\Compiler\AutowiringPass; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Reference; + +/** + * @author Kévin Dunglas + */ +class AutowiringPassTest extends \PHPUnit_Framework_TestCase +{ + public function testProcess() + { + $container = new ContainerBuilder(); + + $container->register('foo', __NAMESPACE__.'\Foo'); + $container->register('bar', __NAMESPACE__.'\Bar'); + + $pass = new AutowiringPass(); + $pass->process($container); + + $this->assertCount(1, $container->getDefinition('bar')->getArguments()); + $this->assertEquals('foo', (string) $container->getDefinition('bar')->getArgument(0)); + } + + public function testProcessAutowireParent() + { + $container = new ContainerBuilder(); + + $container->register('b', __NAMESPACE__.'\B'); + $container->register('c', __NAMESPACE__.'\C'); + + $pass = new AutowiringPass(); + $pass->process($container); + + $this->assertCount(1, $container->getDefinition('c')->getArguments()); + $this->assertEquals('b', (string) $container->getDefinition('c')->getArgument(0)); + } + + public function testProcessAutowireInterface() + { + $container = new ContainerBuilder(); + + $container->register('f', __NAMESPACE__.'\F'); + $container->register('g', __NAMESPACE__.'\G'); + + $pass = new AutowiringPass(); + $pass->process($container); + + $this->assertCount(2, $container->getDefinition('g')->getArguments()); + $this->assertEquals('f', (string) $container->getDefinition('g')->getArgument(0)); + $this->assertEquals('f', (string) $container->getDefinition('g')->getArgument(1)); + } + + public function testCompleteExistingDefinition() + { + $container = new ContainerBuilder(); + + $container->register('b', __NAMESPACE__.'\B'); + $container->register('f', __NAMESPACE__.'\F'); + $container->register('h', __NAMESPACE__.'\H')->addArgument(new Reference('b')); + + $pass = new AutowiringPass(); + $pass->process($container); + + $this->assertCount(2, $container->getDefinition('h')->getArguments()); + $this->assertEquals('b', (string) $container->getDefinition('h')->getArgument(0)); + $this->assertEquals('f', (string) $container->getDefinition('h')->getArgument(1)); + } + + public function testCompleteExistingDefinitionWithNotDefinedArguments() + { + $container = new ContainerBuilder(); + + $container->register('b', __NAMESPACE__.'\B'); + $container->register('f', __NAMESPACE__.'\F'); + $container->register('h', __NAMESPACE__.'\H')->addArgument('')->addArgument(''); + + $pass = new AutowiringPass(); + $pass->process($container); + + $this->assertCount(2, $container->getDefinition('h')->getArguments()); + $this->assertEquals('b', (string) $container->getDefinition('h')->getArgument(0)); + $this->assertEquals('f', (string) $container->getDefinition('h')->getArgument(1)); + } + + /** + * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException + * @expectedExceptionMessage Unable to autowire type "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface". + */ + public function testTypeCollision() + { + $container = new ContainerBuilder(); + + $container->register('c1', __NAMESPACE__.'\CollisionA'); + $container->register('c2', __NAMESPACE__.'\CollisionB'); + $container->register('a', __NAMESPACE__.'\CannotBeAutowired'); + + $pass = new AutowiringPass(); + $pass->process($container); + } + + public function testWithTypeSet() + { + $container = new ContainerBuilder(); + + $container->register('c1', __NAMESPACE__.'\CollisionA'); + $container->register('c2', __NAMESPACE__.'\CollisionB')->addType(__NAMESPACE__.'\CollisionInterface'); + $container->register('a', __NAMESPACE__.'\CannotBeAutowired'); + + $pass = new AutowiringPass(); + $pass->process($container); + + $this->assertCount(1, $container->getDefinition('a')->getArguments()); + $this->assertEquals('c2', (string) $container->getDefinition('a')->getArgument(0)); + } + + public function testCreateDefinition() + { + $container = new ContainerBuilder(); + + $container->register('coop_tilleuls', __NAMESPACE__.'\LesTilleuls'); + + $pass = new AutowiringPass(); + $pass->process($container); + + $this->assertCount(1, $container->getDefinition('coop_tilleuls')->getArguments()); + $this->assertEquals('autowired.symfony\component\dependencyinjection\tests\compiler\dunglas', $container->getDefinition('coop_tilleuls')->getArgument(0)); + + $dunglasDefinition = $container->getDefinition('autowired.symfony\component\dependencyinjection\tests\compiler\dunglas'); + $this->assertEquals(__NAMESPACE__.'\Dunglas', $dunglasDefinition->getClass()); + $this->assertFalse($dunglasDefinition->isPublic()); + $this->assertCount(1, $dunglasDefinition->getArguments()); + $this->assertEquals('autowired.symfony\component\dependencyinjection\tests\compiler\lille', $dunglasDefinition->getArgument(0)); + + $lilleDefinition = $container->getDefinition('autowired.symfony\component\dependencyinjection\tests\compiler\lille'); + $this->assertEquals(__NAMESPACE__.'\Lille', $lilleDefinition->getClass()); + } +} + +class Foo +{ +} + +class Bar +{ + public function __construct(Foo $foo) + { + } +} + +class A +{ +} + +class B extends A +{ +} + +class C +{ + public function __construct(A $a) + { + } +} + +interface DInterface +{ +} + +interface EInterface extends DInterface +{ +} + +class F implements EInterface +{ +} + +class G +{ + public function __construct(DInterface $d, EInterface $e) + { + } +} + +class H +{ + public function __construct(B $b, DInterface $d) + { + } +} + +interface CollisionInterface +{ +} + +class CollisionA implements CollisionInterface +{ +} + +class CollisionB implements CollisionInterface +{ +} + +class CannotBeAutowired +{ + public function __construct(CollisionInterface $collision) + { + } +} + +class Lille +{ +} + +class Dunglas +{ + public function __construct(Lille $l) + { + } +} + +class LesTilleuls +{ + public function __construct(Dunglas $k) + { + } +} diff --git a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php index 047a7cf3347f4..1a4c810239810 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php @@ -890,6 +890,18 @@ public function testLazyLoadedService() $this->assertTrue($classInList); } + + public function testAutowiring() + { + $container = new ContainerBuilder(); + + $container->register('a', __NAMESPACE__.'\A'); + $container->register('b', __NAMESPACE__.'\B'); + + $container->compile(); + + $this->assertEquals('a', (string) $container->getDefinition('b')->getArgument(0)); + } } class FooClass @@ -903,3 +915,14 @@ public function getFoobazService() throw new InactiveScopeException('foo', 'request'); } } + +class A +{ +} + +class B +{ + public function __construct(A $a) + { + } +} diff --git a/src/Symfony/Component/DependencyInjection/Tests/DefinitionTest.php b/src/Symfony/Component/DependencyInjection/Tests/DefinitionTest.php index ea3045df1acbc..fab48f50c746b 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/DefinitionTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/DefinitionTest.php @@ -394,4 +394,17 @@ public function testSetProperty() $this->assertSame($def, $def->setProperty('foo', 'bar')); $this->assertEquals(array('foo' => 'bar'), $def->getProperties()); } + + public function testTypes() + { + $def = new Definition('stdClass'); + + $this->assertEquals(array(), $def->getTypes()); + $this->assertSame($def, $def->setTypes(array('Foo'))); + $this->assertEquals(array('Foo'), $def->getTypes()); + $this->assertSame($def, $def->addType('Bar')); + $this->assertTrue($def->hasType('Bar')); + $this->assertSame($def, $def->removeType('Foo')); + $this->assertEquals(array('Bar'), $def->getTypes()); + } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services22.xml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services22.xml new file mode 100644 index 0000000000000..7b5ffe7c3ca67 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services22.xml @@ -0,0 +1,9 @@ + + + + + Bar + Baz + + + diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/bad_types1.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/bad_types1.yml new file mode 100644 index 0000000000000..79d676f2bf569 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/bad_types1.yml @@ -0,0 +1,5 @@ +services: + foo_service: + class: FooClass + # types is not an array + types: string diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/bad_types2.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/bad_types2.yml new file mode 100644 index 0000000000000..c26e077185723 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/bad_types2.yml @@ -0,0 +1,5 @@ +services: + foo_service: + class: FooClass + # type is not a string + types: [ 1 ] diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services22.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services22.yml new file mode 100644 index 0000000000000..9fa7d0c57b900 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services22.yml @@ -0,0 +1,4 @@ +services: + foo_service: + class: FooClass + types: [ Foo, Bar ] diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php index b717113bb436a..512af94b9ae49 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php @@ -494,4 +494,13 @@ public function testLoadInlinedServices() $this->assertSame('Baz', $barConfigurator[0]->getClass()); $this->assertSame('configureBar', $barConfigurator[1]); } + + public function testType() + { + $container = new ContainerBuilder(); + $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); + $loader->load('services22.xml'); + + $this->assertEquals(array('Bar', 'Baz'), $container->getDefinition('foo')->getTypes()); + } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php index 2d1b0b6956f73..6bfaa5996a72e 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php @@ -282,4 +282,31 @@ public function testLoadYamlOnlyWithKeys() $this->assertEquals(array(true), $definition->getArguments()); $this->assertEquals(array('manager' => array(array('alias' => 'user'))), $definition->getTags()); } + + /** + * @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException + */ + public function testTypesNotArray() + { + $loader = new YamlFileLoader(new ContainerBuilder(), new FileLocator(self::$fixturesPath.'/yaml')); + $loader->load('bad_types1.yml'); + } + + /** + * @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException + */ + public function testTypeNotString() + { + $loader = new YamlFileLoader(new ContainerBuilder(), new FileLocator(self::$fixturesPath.'/yaml')); + $loader->load('bad_types2.yml'); + } + + public function testTypes() + { + $container = new ContainerBuilder(); + $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); + $loader->load('services22.yml'); + + $this->assertEquals(array('Foo', 'Bar'), $container->getDefinition('foo_service')->getTypes()); + } } From 195f6c0abc0ff15ef7cfddf3e14d0283737abdd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Tue, 25 Aug 2015 14:54:58 +0200 Subject: [PATCH 02/19] Fix CS --- .../DependencyInjection/Compiler/AutowiringPass.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AutowiringPass.php b/src/Symfony/Component/DependencyInjection/Compiler/AutowiringPass.php index bae46b85ac88c..4dfc06e11c930 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/AutowiringPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/AutowiringPass.php @@ -45,7 +45,7 @@ public function process(ContainerBuilder $container) /** * Wires the given definition. * - * @param string $id + * @param string $id * @param Definition $definition * * @throws RuntimeException @@ -171,8 +171,8 @@ private function set($type, $value) } unset($this->typesToId[$type]); - $this->notGuessableTypesToId[$type] = true; + return; } @@ -209,7 +209,7 @@ private function createAutowiredDefinition(\ReflectionClass $typeHint) /** * Retrieves the reflection class associated with the given service. * - * @param string $id + * @param string $id * @param Definition $definition * * @return \ReflectionClass|null From 8d23c9d52e40bc04b1bfd37067ce1f3bdd592e7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Tue, 25 Aug 2015 15:04:14 +0200 Subject: [PATCH 03/19] Remove unused argument --- .../Component/DependencyInjection/Compiler/AutowiringPass.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AutowiringPass.php b/src/Symfony/Component/DependencyInjection/Compiler/AutowiringPass.php index 4dfc06e11c930..0f6a49492f2f1 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/AutowiringPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/AutowiringPass.php @@ -38,7 +38,7 @@ public function process(ContainerBuilder $container) $this->container = $container; $this->definitions = $container->getDefinitions(); foreach ($this->definitions as $id => $definition) { - $this->completeDefinition($id, $definition, $container); + $this->completeDefinition($id, $definition); } } From 27f4de83de82d90b19d31d4997deac7caa1eb09d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Tue, 25 Aug 2015 17:11:08 +0200 Subject: [PATCH 04/19] Fix CS --- .../Component/DependencyInjection/Compiler/AutowiringPass.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AutowiringPass.php b/src/Symfony/Component/DependencyInjection/Compiler/AutowiringPass.php index 0f6a49492f2f1..d9cc26c3c4c8a 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/AutowiringPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/AutowiringPass.php @@ -107,7 +107,8 @@ private function populateAvailableTypes() * @param string $id * @param Definition $definition */ - private function populateAvailableType($id, Definition $definition) { + private function populateAvailableType($id, Definition $definition) + { if (!($class = $definition->getClass())) { return; } From 5575ec1d9537fd35c0ad736542f1ed4dd53aac47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Tue, 25 Aug 2015 22:31:37 +0200 Subject: [PATCH 05/19] Fix issues raised by @stof --- .../Compiler/AutowiringPass.php | 66 +++++++++++-------- .../Compiler/PassConfig.php | 2 +- .../Tests/Compiler/AutowiringPassTest.php | 38 +++++++++++ 3 files changed, 79 insertions(+), 27 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AutowiringPass.php b/src/Symfony/Component/DependencyInjection/Compiler/AutowiringPass.php index d9cc26c3c4c8a..30205ad72f962 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/AutowiringPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/AutowiringPass.php @@ -24,11 +24,10 @@ class AutowiringPass implements CompilerPassInterface { private $container; - private $definitions; - private $reflectionClassesToId = array(); + private $reflectionClasses = array(); private $definedTypes = array(); - private $typesToId; - private $notGuessableTypesToId = array(); + private $types; + private $notGuessableTypes = array(); /** * {@inheritdoc} @@ -36,10 +35,16 @@ class AutowiringPass implements CompilerPassInterface public function process(ContainerBuilder $container) { $this->container = $container; - $this->definitions = $container->getDefinitions(); - foreach ($this->definitions as $id => $definition) { + foreach ($container->getDefinitions() as $id => $definition) { $this->completeDefinition($id, $definition); } + + // Free memory and remove circular reference to container + $this->container = null; + $this->reflectionClasses = array(); + $this->definedTypes = array(); + $this->types = null; + $this->notGuessableTypes = array(); } /** @@ -62,7 +67,7 @@ private function completeDefinition($id, Definition $definition) $arguments = $definition->getArguments(); foreach ($constructor->getParameters() as $index => $parameter) { - if (!($typeHint = $parameter->getClass()) || $parameter->isOptional()) { + if (!($typeHint = $parameter->getClass())) { continue; } @@ -71,20 +76,28 @@ private function completeDefinition($id, Definition $definition) continue; } - if (null === $this->typesToId) { + if (null === $this->types) { $this->populateAvailableTypes(); } - if (isset($this->typesToId[$typeHint->name])) { - $reference = new Reference($this->typesToId[$typeHint->name]); + if (isset($this->types[$typeHint->name])) { + $value = new Reference($this->types[$typeHint->name]); } else { - $reference = $this->createAutowiredDefinition($typeHint); + try { + $value = $this->createAutowiredDefinition($typeHint); + } catch (RuntimeException $e) { + if (!$parameter->isDefaultValueAvailable()) { + throw $e; + } + + $value = $parameter->getDefaultValue(); + } } if ($argumentExist) { - $definition->replaceArgument($index, $reference); + $definition->replaceArgument($index, $value); } else { - $definition->addArgument($reference); + $definition->addArgument($value); } } } @@ -94,9 +107,9 @@ private function completeDefinition($id, Definition $definition) */ private function populateAvailableTypes() { - $this->typesToId = array(); + $this->types = array(); - foreach ($this->definitions as $id => $definition) { + foreach ($this->container->getDefinitions() as $id => $definition) { $this->populateAvailableType($id, $definition); } } @@ -115,7 +128,7 @@ private function populateAvailableType($id, Definition $definition) foreach ($definition->getTypes() as $type) { $this->definedTypes[$type] = true; - $this->typesToId[$type] = $id; + $this->types[$type] = $id; } if ($reflectionClass = $this->getReflectionClass($id, $definition)) { @@ -162,22 +175,22 @@ private function extractAncestors($id, \ReflectionClass $reflectionClass) */ private function set($type, $value) { - if (isset($this->definedTypes[$type]) || isset($this->notGuessableTypesToId[$type])) { + if (isset($this->definedTypes[$type]) || isset($this->notGuessableTypes[$type])) { return; } - if (isset($this->typesToId[$type])) { - if ($this->typesToId[$type] === $value) { + if (isset($this->types[$type])) { + if ($this->types[$type] === $value) { return; } - unset($this->typesToId[$type]); - $this->notGuessableTypesToId[$type] = true; + unset($this->types[$type]); + $this->notGuessableTypes[$type] = true; return; } - $this->typesToId[$type] = $value; + $this->types[$type] = $value; } /** @@ -200,7 +213,6 @@ private function createAutowiredDefinition(\ReflectionClass $typeHint) $argumentDefinition = $this->container->register($argumentId, $typeHint->name); $argumentDefinition->setPublic(false); - $this->definitions = $this->container->getDefinitions(); $this->populateAvailableType($argumentId, $argumentDefinition); $this->completeDefinition($argumentId, $argumentDefinition); @@ -217,16 +229,18 @@ private function createAutowiredDefinition(\ReflectionClass $typeHint) */ private function getReflectionClass($id, Definition $definition) { - if (isset($this->reflectionClassesToId[$id])) { - return $this->reflectionClassesToId[$id]; + if (isset($this->reflectionClasses[$id])) { + return $this->reflectionClasses[$id]; } if (!$class = $definition->getClass()) { return; } + $class = $this->container->getParameterBag()->resolveValue($class); + try { - return $this->reflectionClassesToId[$id] = new \ReflectionClass($class); + return $this->reflectionClasses[$id] = new \ReflectionClass($class); } catch (\ReflectionException $e) { // Skip invalid classes definitions to keep BC } diff --git a/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php b/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php index e89a00bb4d19e..efbf8f8023b66 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php @@ -50,8 +50,8 @@ public function __construct() new CheckDefinitionValidityPass(), new ResolveReferencesToAliasesPass(), new ResolveInvalidReferencesPass(), - new AnalyzeServiceReferencesPass(true), new AutowiringPass(), + new AnalyzeServiceReferencesPass(true), new CheckCircularReferencesPass(), new CheckReferenceValidityPass(), ); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowiringPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowiringPassTest.php index f656cc3526674..76c71cc7f1190 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowiringPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowiringPassTest.php @@ -147,6 +147,37 @@ public function testCreateDefinition() $lilleDefinition = $container->getDefinition('autowired.symfony\component\dependencyinjection\tests\compiler\lille'); $this->assertEquals(__NAMESPACE__.'\Lille', $lilleDefinition->getClass()); } + + public function testResolveParameter() + { + $container = new ContainerBuilder(); + + $container->setParameter('class_name', __NAMESPACE__.'\Foo'); + $container->register('foo', '%class_name%'); + $container->register('bar', __NAMESPACE__.'\Bar'); + + $pass = new AutowiringPass(); + $pass->process($container); + + $this->assertEquals('foo', $container->getDefinition('bar')->getArgument(0)); + } + + public function testOptionalParameter() + { + $container = new ContainerBuilder(); + + $container->register('a', __NAMESPACE__.'\A'); + $container->register('foo', __NAMESPACE__.'\Foo'); + $container->register('opt', __NAMESPACE__.'\OptionalParameter'); + + $pass = new AutowiringPass(); + $pass->process($container); + + $definition = $container->getDefinition('opt'); + $this->assertNull($definition->getArgument(0)); + $this->assertEquals('a', $definition->getArgument(1)); + $this->assertEquals('foo', $definition->getArgument(2)); + } } class Foo @@ -237,3 +268,10 @@ public function __construct(Dunglas $k) { } } + +class OptionalParameter +{ + public function __construct(CollisionInterface $c = null, A $a, Foo $f = null) + { + } +} From edce23da281bcf5bc9bcdb6d4ef37e5096eb7f86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Wed, 26 Aug 2015 09:56:03 +0200 Subject: [PATCH 06/19] Better RunTime exception error. --- .../DependencyInjection/Compiler/AutowiringPass.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AutowiringPass.php b/src/Symfony/Component/DependencyInjection/Compiler/AutowiringPass.php index 30205ad72f962..a62e1827424ec 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/AutowiringPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/AutowiringPass.php @@ -84,7 +84,7 @@ private function completeDefinition($id, Definition $definition) $value = new Reference($this->types[$typeHint->name]); } else { try { - $value = $this->createAutowiredDefinition($typeHint); + $value = $this->createAutowiredDefinition($typeHint, $id); } catch (RuntimeException $e) { if (!$parameter->isDefaultValueAvailable()) { throw $e; @@ -197,15 +197,15 @@ private function set($type, $value) * Registers a definition for the type if possible or throws an exception. * * @param \ReflectionClass $typeHint - * + * @param string $id * @return Reference A reference to the registered definition * * @throws RuntimeException */ - private function createAutowiredDefinition(\ReflectionClass $typeHint) + private function createAutowiredDefinition(\ReflectionClass $typeHint, $id) { if (!$typeHint->isInstantiable()) { - throw new RuntimeException(sprintf('Unable to autowire type "%s".', $typeHint->name)); + throw new RuntimeException(sprintf('Unable to autowire argument of type "%s" for the service "%s".', $typeHint->name, $id)); } $argumentId = sprintf('autowired.%s', $typeHint->name); From 07d475ec2941c6808e580d52901fc7f8b49a59a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Wed, 26 Aug 2015 10:20:44 +0200 Subject: [PATCH 07/19] Fix CS --- .../DependencyInjection/Compiler/AutowiringPass.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AutowiringPass.php b/src/Symfony/Component/DependencyInjection/Compiler/AutowiringPass.php index a62e1827424ec..35d4637ba4d06 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/AutowiringPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/AutowiringPass.php @@ -71,8 +71,8 @@ private function completeDefinition($id, Definition $definition) continue; } - $argumentExist = array_key_exists($index, $arguments); - if ($argumentExist && '' !== $arguments[$index]) { + $argumentExists = array_key_exists($index, $arguments); + if ($argumentExists && '' !== $arguments[$index]) { continue; } @@ -94,7 +94,7 @@ private function completeDefinition($id, Definition $definition) } } - if ($argumentExist) { + if ($argumentExists) { $definition->replaceArgument($index, $value); } else { $definition->addArgument($value); @@ -198,6 +198,7 @@ private function set($type, $value) * * @param \ReflectionClass $typeHint * @param string $id + * * @return Reference A reference to the registered definition * * @throws RuntimeException From afe009ad399442b3d1b12c40fb8da6eb1ef036bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Thu, 27 Aug 2015 23:26:51 +0200 Subject: [PATCH 08/19] Flag to enable/disable autowiring. no_autowiring tag. --- .../Resources/config/annotations.xml | 2 ++ .../FrameworkBundle/Resources/config/session.xml | 4 +++- .../Compiler/AutowiringPass.php | 6 +++++- .../DependencyInjection/Compiler/Compiler.php | 6 ++++-- .../DependencyInjection/Compiler/PassConfig.php | 14 +++++++++++--- .../DependencyInjection/ContainerBuilder.php | 2 +- .../Tests/Compiler/AutowiringPassTest.php | 16 +++++++++++++++- src/Symfony/Component/HttpKernel/Kernel.php | 2 ++ 8 files changed, 43 insertions(+), 9 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/annotations.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/annotations.xml index 1c0c312dc2673..e3b121c418687 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/annotations.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/annotations.xml @@ -17,6 +17,8 @@ + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/session.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/session.xml index 591f92e456ddc..59061036669a8 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/session.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/session.xml @@ -55,7 +55,9 @@ %session.save_path% - + + + diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AutowiringPass.php b/src/Symfony/Component/DependencyInjection/Compiler/AutowiringPass.php index 35d4637ba4d06..ac14984864359 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/AutowiringPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/AutowiringPass.php @@ -23,6 +23,8 @@ */ class AutowiringPass implements CompilerPassInterface { + const NO_AUTOWIRING = 'no_autowiring'; + private $container; private $reflectionClasses = array(); private $definedTypes = array(); @@ -36,7 +38,9 @@ public function process(ContainerBuilder $container) { $this->container = $container; foreach ($container->getDefinitions() as $id => $definition) { - $this->completeDefinition($id, $definition); + if (!$definition->hasTag(self::NO_AUTOWIRING)) { + $this->completeDefinition($id, $definition); + } } // Free memory and remove circular reference to container diff --git a/src/Symfony/Component/DependencyInjection/Compiler/Compiler.php b/src/Symfony/Component/DependencyInjection/Compiler/Compiler.php index 4e4c2cdaba5b9..3617b7ab91b29 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/Compiler.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/Compiler.php @@ -27,10 +27,12 @@ class Compiler /** * Constructor. + * + * @param bool $autowiring Enable the autowiring */ - public function __construct() + public function __construct($autowiring = false) { - $this->passConfig = new PassConfig(); + $this->passConfig = new PassConfig($autowiring); $this->serviceReferenceGraph = new ServiceReferenceGraph(); $this->loggingFormatter = new LoggingFormatter(); } diff --git a/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php b/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php index efbf8f8023b66..ecfb52ee81ba4 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php @@ -37,8 +37,10 @@ class PassConfig /** * Constructor. + * + * @param bool $autowiring Enable the autowiring */ - public function __construct() + public function __construct($autowiring = false) { $this->mergePass = new MergeExtensionConfigurationPass(); @@ -50,11 +52,17 @@ public function __construct() new CheckDefinitionValidityPass(), new ResolveReferencesToAliasesPass(), new ResolveInvalidReferencesPass(), - new AutowiringPass(), + ); + + if ($autowiring) { + $this->optimizationPasses[] = new AutowiringPass(); + } + + $this->optimizationPasses = array_merge($this->optimizationPasses, array( new AnalyzeServiceReferencesPass(true), new CheckCircularReferencesPass(), new CheckReferenceValidityPass(), - ); + )); $this->removingPasses = array( new RemovePrivateAliasesPass(), diff --git a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php index 0f893e66e9885..7a1402f7d67e2 100644 --- a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php +++ b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php @@ -325,7 +325,7 @@ public function getCompilerPassConfig() public function getCompiler() { if (null === $this->compiler) { - $this->compiler = new Compiler(); + $this->compiler = new Compiler($this->hasParameter('container.autowiring') ? $this->getParameter('container.autowiring') : false); } return $this->compiler; diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowiringPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowiringPassTest.php index 76c71cc7f1190..d3b801ee916d8 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowiringPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowiringPassTest.php @@ -97,7 +97,7 @@ public function testCompleteExistingDefinitionWithNotDefinedArguments() /** * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException - * @expectedExceptionMessage Unable to autowire type "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface". + * @expectedExceptionMessage Unable to autowire argument of type "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" for the service "a". */ public function testTypeCollision() { @@ -178,6 +178,20 @@ public function testOptionalParameter() $this->assertEquals('a', $definition->getArgument(1)); $this->assertEquals('foo', $definition->getArgument(2)); } + + public function testNoAutowiringTag() + { + $container = new ContainerBuilder(); + + $container->register('foo', __NAMESPACE__.'\Foo'); + $barDefintion = $container->register('bar', __NAMESPACE__.'\Bar'); + $barDefintion->addTag(AutowiringPass::NO_AUTOWIRING); + + $pass = new AutowiringPass(); + $pass->process($container); + + $this->assertCount(0, $container->getDefinition('bar')->getArguments()); + } } class Foo diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 7c55172d395ae..8acb507d32efa 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -59,6 +59,7 @@ abstract class Kernel implements KernelInterface, TerminableInterface protected $name; protected $startTime; protected $loadClassCache; + protected $containerAutowiring = true; const VERSION = '2.8.0-DEV'; const VERSION_ID = 20800; @@ -552,6 +553,7 @@ protected function getKernelParameters() 'kernel.bundles' => $bundles, 'kernel.charset' => $this->getCharset(), 'kernel.container_class' => $this->getContainerClass(), + 'container.autowiring' => $this->containerAutowiring, ), $this->getEnvParameters() ); From 7ab5b0873ed24ec42a5e29455c97140c70966d65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Thu, 27 Aug 2015 23:55:23 +0200 Subject: [PATCH 09/19] Fix some tests --- .../SecurityBundle/Resources/config/security_listeners.xml | 2 ++ src/Symfony/Component/DependencyInjection/Compiler/Compiler.php | 2 +- .../Component/DependencyInjection/Compiler/PassConfig.php | 2 +- src/Symfony/Component/DependencyInjection/ContainerBuilder.php | 2 +- .../DependencyInjection/Tests/ContainerBuilderTest.php | 2 +- 5 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.xml b/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.xml index 948286bb5a857..de134ecffcbb4 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.xml +++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.xml @@ -127,6 +127,8 @@ + + diff --git a/src/Symfony/Component/DependencyInjection/Compiler/Compiler.php b/src/Symfony/Component/DependencyInjection/Compiler/Compiler.php index 3617b7ab91b29..f121bff2772e5 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/Compiler.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/Compiler.php @@ -30,7 +30,7 @@ class Compiler * * @param bool $autowiring Enable the autowiring */ - public function __construct($autowiring = false) + public function __construct($autowiring = true) { $this->passConfig = new PassConfig($autowiring); $this->serviceReferenceGraph = new ServiceReferenceGraph(); diff --git a/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php b/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php index ecfb52ee81ba4..1a97ea063ec2f 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php @@ -40,7 +40,7 @@ class PassConfig * * @param bool $autowiring Enable the autowiring */ - public function __construct($autowiring = false) + public function __construct($autowiring = true) { $this->mergePass = new MergeExtensionConfigurationPass(); diff --git a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php index 7a1402f7d67e2..d9d7d46b770b7 100644 --- a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php +++ b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php @@ -325,7 +325,7 @@ public function getCompilerPassConfig() public function getCompiler() { if (null === $this->compiler) { - $this->compiler = new Compiler($this->hasParameter('container.autowiring') ? $this->getParameter('container.autowiring') : false); + $this->compiler = new Compiler($this->hasParameter('container.autowiring') ? $this->getParameter('container.autowiring') : true); } return $this->compiler; diff --git a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php index 1a4c810239810..aee8adeb24521 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php @@ -893,7 +893,7 @@ public function testLazyLoadedService() public function testAutowiring() { - $container = new ContainerBuilder(); + $container = new ContainerBuilder(new ParameterBag(array('container.autowiring' => true))); $container->register('a', __NAMESPACE__.'\A'); $container->register('b', __NAMESPACE__.'\B'); From a7ca3f231bc426d1f21b86e3e65c37e948b6ee9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Fri, 28 Aug 2015 08:41:33 +0200 Subject: [PATCH 10/19] Fix @meyerbaptiste comments --- .../Compiler/AutowiringPass.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AutowiringPass.php b/src/Symfony/Component/DependencyInjection/Compiler/AutowiringPass.php index ac14984864359..9ece267493c4b 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/AutowiringPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/AutowiringPass.php @@ -119,14 +119,14 @@ private function populateAvailableTypes() } /** - * Populates the of available types for a given definition. + * Populates the list of available types for a given definition. * * @param string $id * @param Definition $definition */ private function populateAvailableType($id, Definition $definition) { - if (!($class = $definition->getClass())) { + if (!$definition->getClass()) { return; } @@ -172,19 +172,19 @@ private function extractAncestors($id, \ReflectionClass $reflectionClass) } /** - * Associates if applicable a type and a service id or a class. + * Associates a type and a service id if applicable. * * @param string $type - * @param string $value A service id or a class name depending of the value of $class + * @param string $id */ - private function set($type, $value) + private function set($type, $id) { if (isset($this->definedTypes[$type]) || isset($this->notGuessableTypes[$type])) { return; } if (isset($this->types[$type])) { - if ($this->types[$type] === $value) { + if ($this->types[$type] === $id) { return; } @@ -194,7 +194,7 @@ private function set($type, $value) return; } - $this->types[$type] = $value; + $this->types[$type] = $id; } /** From 57c494c1fb72836ab12a363cccba1a2c9c2de1e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Fri, 28 Aug 2015 09:00:37 +0200 Subject: [PATCH 11/19] Move the autowiring parameter to a setter --- .../DependencyInjection/ContainerBuilder.php | 24 ++++++++++++++++++- src/Symfony/Component/HttpKernel/Kernel.php | 4 +++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php index d9d7d46b770b7..bed732ec2ddaa 100644 --- a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php +++ b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php @@ -88,6 +88,8 @@ class ContainerBuilder extends Container implements TaggedContainerInterface */ private $expressionLanguageProviders = array(); + private $autowiring = true; + /** * @var string[] with tag names used by findTaggedServiceIds */ @@ -126,6 +128,26 @@ public function setProxyInstantiator(InstantiatorInterface $proxyInstantiator) $this->proxyInstantiator = $proxyInstantiator; } + /** + * Sets if the autowiring must be enabled or not. + * + * @param bool $autowiring + */ + public function setAutowiring($autowiring) + { + $this->autowiring = (bool) $autowiring; + } + + /** + * Checks if the autowiring is enabled. + * + * @return bool + */ + public function isAutowiring() + { + return $this->autowiring; + } + /** * Registers an extension. * @@ -325,7 +347,7 @@ public function getCompilerPassConfig() public function getCompiler() { if (null === $this->compiler) { - $this->compiler = new Compiler($this->hasParameter('container.autowiring') ? $this->getParameter('container.autowiring') : true); + $this->compiler = new Compiler($this->autowiring); } return $this->compiler; diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 8acb507d32efa..b45373f0df13b 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -553,7 +553,6 @@ protected function getKernelParameters() 'kernel.bundles' => $bundles, 'kernel.charset' => $this->getCharset(), 'kernel.container_class' => $this->getContainerClass(), - 'container.autowiring' => $this->containerAutowiring, ), $this->getEnvParameters() ); @@ -645,6 +644,9 @@ protected function prepareContainer(ContainerBuilder $container) protected function getContainerBuilder() { $container = new ContainerBuilder(new ParameterBag($this->getKernelParameters())); + if (!$this->containerAutowiring) { + $container->setAutowiring(false); + } if (class_exists('ProxyManager\Configuration') && class_exists('Symfony\Bridge\ProxyManager\LazyProxy\Instantiator\RuntimeInstantiator')) { $container->setProxyInstantiator(new RuntimeInstantiator()); From e642aa8dd3c182c3edc4d83ce52410212faab09b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Fri, 28 Aug 2015 09:04:55 +0200 Subject: [PATCH 12/19] Fix SecurityBundle test --- .../SecurityBundle/Resources/config/security_listeners.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.xml b/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.xml index de134ecffcbb4..278c29b2dba85 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.xml +++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.xml @@ -139,6 +139,8 @@ + + From d00c7e30ff99cdadaf2088873ae6c3b28f818e13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Fri, 28 Aug 2015 22:29:22 +0200 Subject: [PATCH 13/19] Optin. Removed config flag. --- .../Resources/config/annotations.xml | 2 -- .../Resources/config/session.xml | 4 +-- .../Resources/config/security_listeners.xml | 4 --- .../Compiler/AutowiringPass.php | 10 ++---- .../DependencyInjection/Compiler/Compiler.php | 6 ++-- .../Compiler/PassConfig.php | 14 ++------ .../DependencyInjection/ContainerBuilder.php | 24 +------------ .../Tests/Compiler/AutowiringPassTest.php | 35 ++++++++++++------- .../Tests/ContainerBuilderTest.php | 5 +-- src/Symfony/Component/HttpKernel/Kernel.php | 4 --- 10 files changed, 35 insertions(+), 73 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/annotations.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/annotations.xml index e3b121c418687..1c0c312dc2673 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/annotations.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/annotations.xml @@ -17,8 +17,6 @@ - - diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/session.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/session.xml index 59061036669a8..591f92e456ddc 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/session.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/session.xml @@ -55,9 +55,7 @@ %session.save_path% - - - + diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.xml b/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.xml index 278c29b2dba85..948286bb5a857 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.xml +++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.xml @@ -127,8 +127,6 @@ - - @@ -139,8 +137,6 @@ - - diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AutowiringPass.php b/src/Symfony/Component/DependencyInjection/Compiler/AutowiringPass.php index 9ece267493c4b..3d828b9fd5b22 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/AutowiringPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/AutowiringPass.php @@ -23,7 +23,7 @@ */ class AutowiringPass implements CompilerPassInterface { - const NO_AUTOWIRING = 'no_autowiring'; + const AUTOWIRING = 'autowiring'; private $container; private $reflectionClasses = array(); @@ -38,7 +38,7 @@ public function process(ContainerBuilder $container) { $this->container = $container; foreach ($container->getDefinitions() as $id => $definition) { - if (!$definition->hasTag(self::NO_AUTOWIRING)) { + if ($definition->hasTag(self::AUTOWIRING)) { $this->completeDefinition($id, $definition); } } @@ -244,10 +244,6 @@ private function getReflectionClass($id, Definition $definition) $class = $this->container->getParameterBag()->resolveValue($class); - try { - return $this->reflectionClasses[$id] = new \ReflectionClass($class); - } catch (\ReflectionException $e) { - // Skip invalid classes definitions to keep BC - } + return $this->reflectionClasses[$id] = new \ReflectionClass($class); } } diff --git a/src/Symfony/Component/DependencyInjection/Compiler/Compiler.php b/src/Symfony/Component/DependencyInjection/Compiler/Compiler.php index f121bff2772e5..4e4c2cdaba5b9 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/Compiler.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/Compiler.php @@ -27,12 +27,10 @@ class Compiler /** * Constructor. - * - * @param bool $autowiring Enable the autowiring */ - public function __construct($autowiring = true) + public function __construct() { - $this->passConfig = new PassConfig($autowiring); + $this->passConfig = new PassConfig(); $this->serviceReferenceGraph = new ServiceReferenceGraph(); $this->loggingFormatter = new LoggingFormatter(); } diff --git a/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php b/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php index 1a97ea063ec2f..efbf8f8023b66 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php @@ -37,10 +37,8 @@ class PassConfig /** * Constructor. - * - * @param bool $autowiring Enable the autowiring */ - public function __construct($autowiring = true) + public function __construct() { $this->mergePass = new MergeExtensionConfigurationPass(); @@ -52,17 +50,11 @@ public function __construct($autowiring = true) new CheckDefinitionValidityPass(), new ResolveReferencesToAliasesPass(), new ResolveInvalidReferencesPass(), - ); - - if ($autowiring) { - $this->optimizationPasses[] = new AutowiringPass(); - } - - $this->optimizationPasses = array_merge($this->optimizationPasses, array( + new AutowiringPass(), new AnalyzeServiceReferencesPass(true), new CheckCircularReferencesPass(), new CheckReferenceValidityPass(), - )); + ); $this->removingPasses = array( new RemovePrivateAliasesPass(), diff --git a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php index bed732ec2ddaa..0f893e66e9885 100644 --- a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php +++ b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php @@ -88,8 +88,6 @@ class ContainerBuilder extends Container implements TaggedContainerInterface */ private $expressionLanguageProviders = array(); - private $autowiring = true; - /** * @var string[] with tag names used by findTaggedServiceIds */ @@ -128,26 +126,6 @@ public function setProxyInstantiator(InstantiatorInterface $proxyInstantiator) $this->proxyInstantiator = $proxyInstantiator; } - /** - * Sets if the autowiring must be enabled or not. - * - * @param bool $autowiring - */ - public function setAutowiring($autowiring) - { - $this->autowiring = (bool) $autowiring; - } - - /** - * Checks if the autowiring is enabled. - * - * @return bool - */ - public function isAutowiring() - { - return $this->autowiring; - } - /** * Registers an extension. * @@ -347,7 +325,7 @@ public function getCompilerPassConfig() public function getCompiler() { if (null === $this->compiler) { - $this->compiler = new Compiler($this->autowiring); + $this->compiler = new Compiler(); } return $this->compiler; diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowiringPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowiringPassTest.php index d3b801ee916d8..b0c98763754cc 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowiringPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowiringPassTest.php @@ -25,7 +25,8 @@ public function testProcess() $container = new ContainerBuilder(); $container->register('foo', __NAMESPACE__.'\Foo'); - $container->register('bar', __NAMESPACE__.'\Bar'); + $barDefinition = $container->register('bar', __NAMESPACE__.'\Bar'); + $barDefinition->addTag(AutowiringPass::AUTOWIRING); $pass = new AutowiringPass(); $pass->process($container); @@ -39,7 +40,8 @@ public function testProcessAutowireParent() $container = new ContainerBuilder(); $container->register('b', __NAMESPACE__.'\B'); - $container->register('c', __NAMESPACE__.'\C'); + $cDefinition = $container->register('c', __NAMESPACE__.'\C'); + $cDefinition->addTag(AutowiringPass::AUTOWIRING); $pass = new AutowiringPass(); $pass->process($container); @@ -53,7 +55,8 @@ public function testProcessAutowireInterface() $container = new ContainerBuilder(); $container->register('f', __NAMESPACE__.'\F'); - $container->register('g', __NAMESPACE__.'\G'); + $gDefinition = $container->register('g', __NAMESPACE__.'\G'); + $gDefinition->addTag(AutowiringPass::AUTOWIRING); $pass = new AutowiringPass(); $pass->process($container); @@ -69,7 +72,8 @@ public function testCompleteExistingDefinition() $container->register('b', __NAMESPACE__.'\B'); $container->register('f', __NAMESPACE__.'\F'); - $container->register('h', __NAMESPACE__.'\H')->addArgument(new Reference('b')); + $hDefinition = $container->register('h', __NAMESPACE__.'\H')->addArgument(new Reference('b')); + $hDefinition->addTag(AutowiringPass::AUTOWIRING); $pass = new AutowiringPass(); $pass->process($container); @@ -85,7 +89,8 @@ public function testCompleteExistingDefinitionWithNotDefinedArguments() $container->register('b', __NAMESPACE__.'\B'); $container->register('f', __NAMESPACE__.'\F'); - $container->register('h', __NAMESPACE__.'\H')->addArgument('')->addArgument(''); + $hDefinition = $container->register('h', __NAMESPACE__.'\H')->addArgument('')->addArgument(''); + $hDefinition->addTag(AutowiringPass::AUTOWIRING); $pass = new AutowiringPass(); $pass->process($container); @@ -105,7 +110,8 @@ public function testTypeCollision() $container->register('c1', __NAMESPACE__.'\CollisionA'); $container->register('c2', __NAMESPACE__.'\CollisionB'); - $container->register('a', __NAMESPACE__.'\CannotBeAutowired'); + $aDefinition = $container->register('a', __NAMESPACE__.'\CannotBeAutowired'); + $aDefinition->addTag(AutowiringPass::AUTOWIRING); $pass = new AutowiringPass(); $pass->process($container); @@ -117,7 +123,8 @@ public function testWithTypeSet() $container->register('c1', __NAMESPACE__.'\CollisionA'); $container->register('c2', __NAMESPACE__.'\CollisionB')->addType(__NAMESPACE__.'\CollisionInterface'); - $container->register('a', __NAMESPACE__.'\CannotBeAutowired'); + $aDefinition = $container->register('a', __NAMESPACE__.'\CannotBeAutowired'); + $aDefinition->addTag(AutowiringPass::AUTOWIRING); $pass = new AutowiringPass(); $pass->process($container); @@ -130,7 +137,8 @@ public function testCreateDefinition() { $container = new ContainerBuilder(); - $container->register('coop_tilleuls', __NAMESPACE__.'\LesTilleuls'); + $coopTilleulsDefinition = $container->register('coop_tilleuls', __NAMESPACE__.'\LesTilleuls'); + $coopTilleulsDefinition->addTag(AutowiringPass::AUTOWIRING); $pass = new AutowiringPass(); $pass->process($container); @@ -154,7 +162,8 @@ public function testResolveParameter() $container->setParameter('class_name', __NAMESPACE__.'\Foo'); $container->register('foo', '%class_name%'); - $container->register('bar', __NAMESPACE__.'\Bar'); + $barDefinition = $container->register('bar', __NAMESPACE__.'\Bar'); + $barDefinition->addTag(AutowiringPass::AUTOWIRING); $pass = new AutowiringPass(); $pass->process($container); @@ -168,7 +177,8 @@ public function testOptionalParameter() $container->register('a', __NAMESPACE__.'\A'); $container->register('foo', __NAMESPACE__.'\Foo'); - $container->register('opt', __NAMESPACE__.'\OptionalParameter'); + $optDefinition = $container->register('opt', __NAMESPACE__.'\OptionalParameter'); + $optDefinition->addTag(AutowiringPass::AUTOWIRING); $pass = new AutowiringPass(); $pass->process($container); @@ -179,13 +189,12 @@ public function testOptionalParameter() $this->assertEquals('foo', $definition->getArgument(2)); } - public function testNoAutowiringTag() + public function testDontTriggeruAutowiring() { $container = new ContainerBuilder(); $container->register('foo', __NAMESPACE__.'\Foo'); - $barDefintion = $container->register('bar', __NAMESPACE__.'\Bar'); - $barDefintion->addTag(AutowiringPass::NO_AUTOWIRING); + $container->register('bar', __NAMESPACE__.'\Bar'); $pass = new AutowiringPass(); $pass->process($container); diff --git a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php index aee8adeb24521..f301e7b3d6fc0 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php @@ -893,10 +893,11 @@ public function testLazyLoadedService() public function testAutowiring() { - $container = new ContainerBuilder(new ParameterBag(array('container.autowiring' => true))); + $container = new ContainerBuilder(); $container->register('a', __NAMESPACE__.'\A'); - $container->register('b', __NAMESPACE__.'\B'); + $bDefinition = $container->register('b', __NAMESPACE__.'\B'); + $bDefinition->addTag('autowiring'); $container->compile(); diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index b45373f0df13b..7c55172d395ae 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -59,7 +59,6 @@ abstract class Kernel implements KernelInterface, TerminableInterface protected $name; protected $startTime; protected $loadClassCache; - protected $containerAutowiring = true; const VERSION = '2.8.0-DEV'; const VERSION_ID = 20800; @@ -644,9 +643,6 @@ protected function prepareContainer(ContainerBuilder $container) protected function getContainerBuilder() { $container = new ContainerBuilder(new ParameterBag($this->getKernelParameters())); - if (!$this->containerAutowiring) { - $container->setAutowiring(false); - } if (class_exists('ProxyManager\Configuration') && class_exists('Symfony\Bridge\ProxyManager\LazyProxy\Instantiator\RuntimeInstantiator')) { $container->setProxyInstantiator(new RuntimeInstantiator()); From 55bb42c15d688d6c202a0e296699e994e8008487 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Sun, 30 Aug 2015 15:18:11 +0200 Subject: [PATCH 14/19] Fix CS --- src/Symfony/Component/DependencyInjection/Definition.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/DependencyInjection/Definition.php b/src/Symfony/Component/DependencyInjection/Definition.php index 0bcd11b0263c7..b2a80902347ef 100644 --- a/src/Symfony/Component/DependencyInjection/Definition.php +++ b/src/Symfony/Component/DependencyInjection/Definition.php @@ -883,7 +883,8 @@ public function removeType($type) * * @return bool */ - public function hasType($type) { + public function hasType($type) + { return isset($this->types[$type]); } } From 7806487bbb3455ee1518f8b9f37ac160f2f014be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Thu, 24 Sep 2015 19:45:33 +0200 Subject: [PATCH 15/19] [DependencyInjection] Rename types to autowiring_types --- .../Compiler/AutowiringPass.php | 2 +- .../DependencyInjection/Definition.php | 24 +++++++++---------- .../Loader/XmlFileLoader.php | 4 ++-- .../Loader/YamlFileLoader.php | 14 +++++------ .../schema/dic/services/services-1.0.xsd | 2 +- .../Tests/Compiler/AutowiringPassTest.php | 2 +- .../Tests/DefinitionTest.php | 12 +++++----- .../Tests/Fixtures/xml/services22.xml | 4 ++-- .../Tests/Fixtures/yaml/bad_types1.yml | 4 ++-- .../Tests/Fixtures/yaml/bad_types2.yml | 6 ++--- .../Tests/Fixtures/yaml/services22.yml | 4 ++-- .../Tests/Loader/XmlFileLoaderTest.php | 2 +- .../Tests/Loader/YamlFileLoaderTest.php | 2 +- 13 files changed, 41 insertions(+), 41 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AutowiringPass.php b/src/Symfony/Component/DependencyInjection/Compiler/AutowiringPass.php index 3d828b9fd5b22..b570225148939 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/AutowiringPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/AutowiringPass.php @@ -130,7 +130,7 @@ private function populateAvailableType($id, Definition $definition) return; } - foreach ($definition->getTypes() as $type) { + foreach ($definition->getAutowiringTypes() as $type) { $this->definedTypes[$type] = true; $this->types[$type] = $id; } diff --git a/src/Symfony/Component/DependencyInjection/Definition.php b/src/Symfony/Component/DependencyInjection/Definition.php index b2a80902347ef..8c8212711c686 100644 --- a/src/Symfony/Component/DependencyInjection/Definition.php +++ b/src/Symfony/Component/DependencyInjection/Definition.php @@ -41,7 +41,7 @@ class Definition private $synchronized = false; private $lazy = false; private $decoratedService; - private $types = array(); + private $autowiringTypes = array(); protected $arguments; @@ -829,23 +829,23 @@ public function getConfigurator() */ public function setTypes(array $types) { - $this->types = array(); + $this->autowiringTypes = array(); foreach ($types as $type) { - $this->types[$type] = true; + $this->autowiringTypes[$type] = true; } return $this; } /** - * Gets types that will default to this definition. + * Gets autowiring types that will default to this definition. * * @return string[] */ - public function getTypes() + public function getAutowiringTypes() { - return array_keys($this->types); + return array_keys($this->autowiringTypes); } /** @@ -855,9 +855,9 @@ public function getTypes() * * @return Definition The current instance */ - public function addType($type) + public function addAutowiringType($type) { - $this->types[$type] = true; + $this->autowiringTypes[$type] = true; return $this; } @@ -869,9 +869,9 @@ public function addType($type) * * @return Definition The current instance */ - public function removeType($type) + public function removeAutowiringType($type) { - unset($this->types[$type]); + unset($this->autowiringTypes[$type]); return $this; } @@ -883,8 +883,8 @@ public function removeType($type) * * @return bool */ - public function hasType($type) + public function hasAutowiringType($type) { - return isset($this->types[$type]); + return isset($this->autowiringTypes[$type]); } } diff --git a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php index fa2c3f9234f6b..20ab3688019dd 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php @@ -247,8 +247,8 @@ private function parseDefinition(\DOMElement $service, $file) $definition->addTag($tag->getAttribute('name'), $parameters); } - foreach ($this->getChildren($service, 'type') as $type) { - $definition->addType($type->textContent); + foreach ($this->getChildren($service, 'autowiring-type') as $type) { + $definition->addAutowiringType($type->textContent); } if ($value = $service->getAttribute('decorates')) { diff --git a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php index 508c65144b7c6..7d49f708de7f1 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php @@ -299,17 +299,17 @@ private function parseDefinition($id, $service, $file) $definition->setDecoratedService($service['decorates'], $renameId, $priority); } - if (isset($service['types'])) { - if (!is_array($service['types'])) { - throw new InvalidArgumentException(sprintf('Parameter "types" must be an array for service "%s" in %s. Check your YAML syntax.', $id, $file)); + if (isset($service['autowiring_types'])) { + if (!is_array($service['autowiring_types'])) { + throw new InvalidArgumentException(sprintf('Parameter "autowiring_types" must be an array for service "%s" in %s. Check your YAML syntax.', $id, $file)); } - foreach ($service['types'] as $type) { - if (!is_string($type)) { - throw new InvalidArgumentException(sprintf('A "types" attribute must be of type string for service "%s" in %s. Check your YAML syntax.', $id, $file)); + foreach ($service['autowiring_types'] as $autowiringType) { + if (!is_string($autowiringType)) { + throw new InvalidArgumentException(sprintf('A "autowiring_types" attribute must be of type string for service "%s" in %s. Check your YAML syntax.', $id, $file)); } - $definition->addType($type); + $definition->addAutowiringType($autowiringType); } } 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 1bf4eb5bc0859..95fb3cfbd3fb1 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 @@ -85,7 +85,7 @@ - + diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowiringPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowiringPassTest.php index b0c98763754cc..69751695792ad 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowiringPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowiringPassTest.php @@ -122,7 +122,7 @@ public function testWithTypeSet() $container = new ContainerBuilder(); $container->register('c1', __NAMESPACE__.'\CollisionA'); - $container->register('c2', __NAMESPACE__.'\CollisionB')->addType(__NAMESPACE__.'\CollisionInterface'); + $container->register('c2', __NAMESPACE__.'\CollisionB')->addAutowiringType(__NAMESPACE__.'\CollisionInterface'); $aDefinition = $container->register('a', __NAMESPACE__.'\CannotBeAutowired'); $aDefinition->addTag(AutowiringPass::AUTOWIRING); diff --git a/src/Symfony/Component/DependencyInjection/Tests/DefinitionTest.php b/src/Symfony/Component/DependencyInjection/Tests/DefinitionTest.php index fab48f50c746b..ccc4ecfbb99de 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/DefinitionTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/DefinitionTest.php @@ -399,12 +399,12 @@ public function testTypes() { $def = new Definition('stdClass'); - $this->assertEquals(array(), $def->getTypes()); + $this->assertEquals(array(), $def->getAutowiringTypes()); $this->assertSame($def, $def->setTypes(array('Foo'))); - $this->assertEquals(array('Foo'), $def->getTypes()); - $this->assertSame($def, $def->addType('Bar')); - $this->assertTrue($def->hasType('Bar')); - $this->assertSame($def, $def->removeType('Foo')); - $this->assertEquals(array('Bar'), $def->getTypes()); + $this->assertEquals(array('Foo'), $def->getAutowiringTypes()); + $this->assertSame($def, $def->addAutowiringType('Bar')); + $this->assertTrue($def->hasAutowiringType('Bar')); + $this->assertSame($def, $def->removeAutowiringType('Foo')); + $this->assertEquals(array('Bar'), $def->getAutowiringTypes()); } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services22.xml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services22.xml index 7b5ffe7c3ca67..fa79d389489fb 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services22.xml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services22.xml @@ -2,8 +2,8 @@ - Bar - Baz + Bar + Baz diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/bad_types1.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/bad_types1.yml index 79d676f2bf569..a9572c4d00a53 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/bad_types1.yml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/bad_types1.yml @@ -1,5 +1,5 @@ services: foo_service: - class: FooClass + class: FooClass # types is not an array - types: string + autowiring_types: string diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/bad_types2.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/bad_types2.yml index c26e077185723..fb1d53e151014 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/bad_types2.yml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/bad_types2.yml @@ -1,5 +1,5 @@ services: foo_service: - class: FooClass - # type is not a string - types: [ 1 ] + class: FooClass + # autowiring_types is not a string + autowiring_types: [ 1 ] diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services22.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services22.yml index 9fa7d0c57b900..ed61ad50ac559 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services22.yml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services22.yml @@ -1,4 +1,4 @@ services: foo_service: - class: FooClass - types: [ Foo, Bar ] + class: FooClass + autowiring_types: [ Foo, Bar ] diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php index 512af94b9ae49..f0e3d7b99c243 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php @@ -501,6 +501,6 @@ public function testType() $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); $loader->load('services22.xml'); - $this->assertEquals(array('Bar', 'Baz'), $container->getDefinition('foo')->getTypes()); + $this->assertEquals(array('Bar', 'Baz'), $container->getDefinition('foo')->getAutowiringTypes()); } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php index 6bfaa5996a72e..a29fb1f69b7dd 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php @@ -307,6 +307,6 @@ public function testTypes() $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); $loader->load('services22.yml'); - $this->assertEquals(array('Foo', 'Bar'), $container->getDefinition('foo_service')->getTypes()); + $this->assertEquals(array('Foo', 'Bar'), $container->getDefinition('foo_service')->getAutowiringTypes()); } } From 585616dc4189614d92d3fcc1d64e20dad25452f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Mon, 28 Sep 2015 09:34:28 +0200 Subject: [PATCH 16/19] [DependencyInjection] Add the new 'autowire' syntax. --- .../{AutowiringPass.php => AutowirePass.php} | 7 ++- .../Compiler/PassConfig.php | 2 +- .../DependencyInjection/Definition.php | 25 ++++++++++ .../Loader/XmlFileLoader.php | 4 ++ .../Loader/YamlFileLoader.php | 4 ++ .../schema/dic/services/services-1.0.xsd | 1 + ...iringPassTest.php => AutowirePassTest.php} | 46 +++++++++---------- .../Tests/DefinitionTest.php | 8 ++++ .../Tests/Fixtures/xml/services23.xml | 6 +++ .../Tests/Fixtures/yaml/services23.yml | 4 ++ .../Tests/Loader/XmlFileLoaderTest.php | 9 ++++ .../Tests/Loader/YamlFileLoaderTest.php | 9 ++++ 12 files changed, 97 insertions(+), 28 deletions(-) rename src/Symfony/Component/DependencyInjection/Compiler/{AutowiringPass.php => AutowirePass.php} (97%) rename src/Symfony/Component/DependencyInjection/Tests/Compiler/{AutowiringPassTest.php => AutowirePassTest.php} (87%) create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services23.xml create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services23.yml diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AutowiringPass.php b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php similarity index 97% rename from src/Symfony/Component/DependencyInjection/Compiler/AutowiringPass.php rename to src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php index b570225148939..bc268845191f4 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/AutowiringPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php @@ -21,10 +21,8 @@ * * @author Kévin Dunglas */ -class AutowiringPass implements CompilerPassInterface +class AutowirePass implements CompilerPassInterface { - const AUTOWIRING = 'autowiring'; - private $container; private $reflectionClasses = array(); private $definedTypes = array(); @@ -38,7 +36,7 @@ public function process(ContainerBuilder $container) { $this->container = $container; foreach ($container->getDefinitions() as $id => $definition) { - if ($definition->hasTag(self::AUTOWIRING)) { + if ($definition->isAutowired()) { $this->completeDefinition($id, $definition); } } @@ -64,6 +62,7 @@ private function completeDefinition($id, Definition $definition) if (!($reflectionClass = $this->getReflectionClass($id, $definition))) { return; } + $this->container->addClassResource($reflectionClass); if (!($constructor = $reflectionClass->getConstructor())) { return; diff --git a/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php b/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php index efbf8f8023b66..246529d865cd3 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php @@ -50,7 +50,7 @@ public function __construct() new CheckDefinitionValidityPass(), new ResolveReferencesToAliasesPass(), new ResolveInvalidReferencesPass(), - new AutowiringPass(), + new AutowirePass(), new AnalyzeServiceReferencesPass(true), new CheckCircularReferencesPass(), new CheckReferenceValidityPass(), diff --git a/src/Symfony/Component/DependencyInjection/Definition.php b/src/Symfony/Component/DependencyInjection/Definition.php index 8c8212711c686..30fc9c99655fd 100644 --- a/src/Symfony/Component/DependencyInjection/Definition.php +++ b/src/Symfony/Component/DependencyInjection/Definition.php @@ -41,6 +41,7 @@ class Definition private $synchronized = false; private $lazy = false; private $decoratedService; + private $autowired = false; private $autowiringTypes = array(); protected $arguments; @@ -838,6 +839,30 @@ public function setTypes(array $types) return $this; } + /** + * Is the definition autowired? + * + * @return bool + */ + public function isAutowired() + { + return $this->autowired; + } + + /** + * Sets autowired. + * + * @param $autowired + * + * @return Definition The current instance + */ + public function setAutowired($autowired) + { + $this->autowired = $autowired; + + return $this; + } + /** * Gets autowiring types that will default to this definition. * diff --git a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php index 20ab3688019dd..7fb98972c0c6e 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php @@ -157,6 +157,10 @@ private function parseDefinition(\DOMElement $service, $file) } } + if ($value = $service->getAttribute('autowire')) { + $definition->setAutowired(XmlUtils::phpize($value)); + } + if ($value = $service->getAttribute('scope')) { $triggerDeprecation = 'request' !== (string) $service->getAttribute('id'); diff --git a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php index 7d49f708de7f1..3811644dc69c0 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php @@ -299,6 +299,10 @@ private function parseDefinition($id, $service, $file) $definition->setDecoratedService($service['decorates'], $renameId, $priority); } + if (isset($service['autowire'])) { + $definition->setAutowired($service['autowire']); + } + if (isset($service['autowiring_types'])) { if (!is_array($service['autowiring_types'])) { throw new InvalidArgumentException(sprintf('Parameter "autowiring_types" must be an array for service "%s" in %s. Check your YAML syntax.', $id, $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 95fb3cfbd3fb1..3241c43c40994 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 @@ -104,6 +104,7 @@ + diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowiringPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php similarity index 87% rename from src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowiringPassTest.php rename to src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php index 69751695792ad..3639a2138fad7 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowiringPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php @@ -11,14 +11,14 @@ namespace Symfony\Component\DependencyInjection\Tests\Compiler; -use Symfony\Component\DependencyInjection\Compiler\AutowiringPass; +use Symfony\Component\DependencyInjection\Compiler\AutowirePass; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; /** * @author Kévin Dunglas */ -class AutowiringPassTest extends \PHPUnit_Framework_TestCase +class AutowirePassTest extends \PHPUnit_Framework_TestCase { public function testProcess() { @@ -26,9 +26,9 @@ public function testProcess() $container->register('foo', __NAMESPACE__.'\Foo'); $barDefinition = $container->register('bar', __NAMESPACE__.'\Bar'); - $barDefinition->addTag(AutowiringPass::AUTOWIRING); + $barDefinition->setAutowired(true); - $pass = new AutowiringPass(); + $pass = new AutowirePass(); $pass->process($container); $this->assertCount(1, $container->getDefinition('bar')->getArguments()); @@ -41,9 +41,9 @@ public function testProcessAutowireParent() $container->register('b', __NAMESPACE__.'\B'); $cDefinition = $container->register('c', __NAMESPACE__.'\C'); - $cDefinition->addTag(AutowiringPass::AUTOWIRING); + $cDefinition->setAutowired(true); - $pass = new AutowiringPass(); + $pass = new AutowirePass(); $pass->process($container); $this->assertCount(1, $container->getDefinition('c')->getArguments()); @@ -56,9 +56,9 @@ public function testProcessAutowireInterface() $container->register('f', __NAMESPACE__.'\F'); $gDefinition = $container->register('g', __NAMESPACE__.'\G'); - $gDefinition->addTag(AutowiringPass::AUTOWIRING); + $gDefinition->setAutowired(true); - $pass = new AutowiringPass(); + $pass = new AutowirePass(); $pass->process($container); $this->assertCount(2, $container->getDefinition('g')->getArguments()); @@ -73,9 +73,9 @@ public function testCompleteExistingDefinition() $container->register('b', __NAMESPACE__.'\B'); $container->register('f', __NAMESPACE__.'\F'); $hDefinition = $container->register('h', __NAMESPACE__.'\H')->addArgument(new Reference('b')); - $hDefinition->addTag(AutowiringPass::AUTOWIRING); + $hDefinition->setAutowired(true); - $pass = new AutowiringPass(); + $pass = new AutowirePass(); $pass->process($container); $this->assertCount(2, $container->getDefinition('h')->getArguments()); @@ -90,9 +90,9 @@ public function testCompleteExistingDefinitionWithNotDefinedArguments() $container->register('b', __NAMESPACE__.'\B'); $container->register('f', __NAMESPACE__.'\F'); $hDefinition = $container->register('h', __NAMESPACE__.'\H')->addArgument('')->addArgument(''); - $hDefinition->addTag(AutowiringPass::AUTOWIRING); + $hDefinition->setAutowired(true); - $pass = new AutowiringPass(); + $pass = new AutowirePass(); $pass->process($container); $this->assertCount(2, $container->getDefinition('h')->getArguments()); @@ -111,9 +111,9 @@ public function testTypeCollision() $container->register('c1', __NAMESPACE__.'\CollisionA'); $container->register('c2', __NAMESPACE__.'\CollisionB'); $aDefinition = $container->register('a', __NAMESPACE__.'\CannotBeAutowired'); - $aDefinition->addTag(AutowiringPass::AUTOWIRING); + $aDefinition->setAutowired(true); - $pass = new AutowiringPass(); + $pass = new AutowirePass(); $pass->process($container); } @@ -124,9 +124,9 @@ public function testWithTypeSet() $container->register('c1', __NAMESPACE__.'\CollisionA'); $container->register('c2', __NAMESPACE__.'\CollisionB')->addAutowiringType(__NAMESPACE__.'\CollisionInterface'); $aDefinition = $container->register('a', __NAMESPACE__.'\CannotBeAutowired'); - $aDefinition->addTag(AutowiringPass::AUTOWIRING); + $aDefinition->setAutowired(true); - $pass = new AutowiringPass(); + $pass = new AutowirePass(); $pass->process($container); $this->assertCount(1, $container->getDefinition('a')->getArguments()); @@ -138,9 +138,9 @@ public function testCreateDefinition() $container = new ContainerBuilder(); $coopTilleulsDefinition = $container->register('coop_tilleuls', __NAMESPACE__.'\LesTilleuls'); - $coopTilleulsDefinition->addTag(AutowiringPass::AUTOWIRING); + $coopTilleulsDefinition->setAutowired(true); - $pass = new AutowiringPass(); + $pass = new AutowirePass(); $pass->process($container); $this->assertCount(1, $container->getDefinition('coop_tilleuls')->getArguments()); @@ -163,9 +163,9 @@ public function testResolveParameter() $container->setParameter('class_name', __NAMESPACE__.'\Foo'); $container->register('foo', '%class_name%'); $barDefinition = $container->register('bar', __NAMESPACE__.'\Bar'); - $barDefinition->addTag(AutowiringPass::AUTOWIRING); + $barDefinition->setAutowired(true); - $pass = new AutowiringPass(); + $pass = new AutowirePass(); $pass->process($container); $this->assertEquals('foo', $container->getDefinition('bar')->getArgument(0)); @@ -178,9 +178,9 @@ public function testOptionalParameter() $container->register('a', __NAMESPACE__.'\A'); $container->register('foo', __NAMESPACE__.'\Foo'); $optDefinition = $container->register('opt', __NAMESPACE__.'\OptionalParameter'); - $optDefinition->addTag(AutowiringPass::AUTOWIRING); + $optDefinition->setAutowired(true); - $pass = new AutowiringPass(); + $pass = new AutowirePass(); $pass->process($container); $definition = $container->getDefinition('opt'); @@ -196,7 +196,7 @@ public function testDontTriggeruAutowiring() $container->register('foo', __NAMESPACE__.'\Foo'); $container->register('bar', __NAMESPACE__.'\Bar'); - $pass = new AutowiringPass(); + $pass = new AutowirePass(); $pass->process($container); $this->assertCount(0, $container->getDefinition('bar')->getArguments()); diff --git a/src/Symfony/Component/DependencyInjection/Tests/DefinitionTest.php b/src/Symfony/Component/DependencyInjection/Tests/DefinitionTest.php index ccc4ecfbb99de..47288af7686ea 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/DefinitionTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/DefinitionTest.php @@ -395,6 +395,14 @@ public function testSetProperty() $this->assertEquals(array('foo' => 'bar'), $def->getProperties()); } + public function testAutowired() + { + $def = new Definition('stdClass'); + $this->assertFalse($def->isAutowired()); + $def->setAutowired(true); + $this->assertTrue($def->isAutowired()); + } + public function testTypes() { $def = new Definition('stdClass'); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services23.xml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services23.xml new file mode 100644 index 0000000000000..3f9e15fd499da --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services23.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services23.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services23.yml new file mode 100644 index 0000000000000..1984c17714633 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services23.yml @@ -0,0 +1,4 @@ +services: + bar_service: + class: BarClass + autowire: true diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php index f0e3d7b99c243..723d30605ea4e 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php @@ -503,4 +503,13 @@ public function testType() $this->assertEquals(array('Bar', 'Baz'), $container->getDefinition('foo')->getAutowiringTypes()); } + + public function testAutowire() + { + $container = new ContainerBuilder(); + $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); + $loader->load('services23.xml'); + + $this->assertTrue($container->getDefinition('bar')->isAutowired()); + } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php index a29fb1f69b7dd..8b1004f1552bb 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php @@ -309,4 +309,13 @@ public function testTypes() $this->assertEquals(array('Foo', 'Bar'), $container->getDefinition('foo_service')->getAutowiringTypes()); } + + public function testAutowire() + { + $container = new ContainerBuilder(); + $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); + $loader->load('services23.yml'); + + $this->assertTrue($container->getDefinition('bar_service')->isAutowired()); + } } From c717c694287b20c85febe14aef29847adb101e5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Mon, 28 Sep 2015 14:11:59 +0200 Subject: [PATCH 17/19] Fix tests. --- .../DependencyInjection/Tests/ContainerBuilderTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php index f301e7b3d6fc0..ad83f8e0d13f3 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php @@ -897,7 +897,7 @@ public function testAutowiring() $container->register('a', __NAMESPACE__.'\A'); $bDefinition = $container->register('b', __NAMESPACE__.'\B'); - $bDefinition->addTag('autowiring'); + $bDefinition->setAutowired(true); $container->compile(); From 3b7f5538643a5b25e8e5c4060a50826fc34d59f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Fri, 2 Oct 2015 11:50:40 +0200 Subject: [PATCH 18/19] Fix @fabpot and @stof comments. --- .../Compiler/AutowirePass.php | 13 ++++++++---- .../DependencyInjection/Definition.php | 2 +- .../Loader/YamlFileLoader.php | 20 +++++++++++-------- .../Tests/DefinitionTest.php | 2 +- .../Tests/Fixtures/yaml/bad_types1.yml | 2 +- .../Tests/Fixtures/yaml/services22.yml | 4 ++++ .../Tests/Loader/YamlFileLoaderTest.php | 1 + 7 files changed, 29 insertions(+), 15 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php index bc268845191f4..45951ab9df7da 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php @@ -59,18 +59,19 @@ public function process(ContainerBuilder $container) */ private function completeDefinition($id, Definition $definition) { - if (!($reflectionClass = $this->getReflectionClass($id, $definition))) { + if (!$reflectionClass = $this->getReflectionClass($id, $definition)) { return; } + $this->container->addClassResource($reflectionClass); - if (!($constructor = $reflectionClass->getConstructor())) { + if (!$constructor = $reflectionClass->getConstructor()) { return; } $arguments = $definition->getArguments(); foreach ($constructor->getParameters() as $index => $parameter) { - if (!($typeHint = $parameter->getClass())) { + if (!$typeHint = $parameter->getClass()) { continue; } @@ -243,6 +244,10 @@ private function getReflectionClass($id, Definition $definition) $class = $this->container->getParameterBag()->resolveValue($class); - return $this->reflectionClasses[$id] = new \ReflectionClass($class); + try { + return $this->reflectionClasses[$id] = new \ReflectionClass($class); + } catch (\ReflectionException $reflectionException) { + // return null + } } } diff --git a/src/Symfony/Component/DependencyInjection/Definition.php b/src/Symfony/Component/DependencyInjection/Definition.php index 30fc9c99655fd..66ea2cc0e4146 100644 --- a/src/Symfony/Component/DependencyInjection/Definition.php +++ b/src/Symfony/Component/DependencyInjection/Definition.php @@ -828,7 +828,7 @@ public function getConfigurator() * * @return Definition The current instance */ - public function setTypes(array $types) + public function setAutowiringTypes(array $types) { $this->autowiringTypes = array(); diff --git a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php index 3811644dc69c0..3039885ec2fc9 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php @@ -304,16 +304,20 @@ private function parseDefinition($id, $service, $file) } if (isset($service['autowiring_types'])) { - if (!is_array($service['autowiring_types'])) { - throw new InvalidArgumentException(sprintf('Parameter "autowiring_types" must be an array for service "%s" in %s. Check your YAML syntax.', $id, $file)); - } - - foreach ($service['autowiring_types'] as $autowiringType) { - if (!is_string($autowiringType)) { - throw new InvalidArgumentException(sprintf('A "autowiring_types" attribute must be of type string for service "%s" in %s. Check your YAML syntax.', $id, $file)); + if (is_string($service['autowiring_types'])) { + $definition->addAutowiringType($service['autowiring_types']); + } else { + if (!is_array($service['autowiring_types'])) { + throw new InvalidArgumentException(sprintf('Parameter "autowiring_types" must be a string or an array for service "%s" in %s. Check your YAML syntax.', $id, $file)); } - $definition->addAutowiringType($autowiringType); + foreach ($service['autowiring_types'] as $autowiringType) { + if (!is_string($autowiringType)) { + throw new InvalidArgumentException(sprintf('A "autowiring_types" attribute must be of type string for service "%s" in %s. Check your YAML syntax.', $id, $file)); + } + + $definition->addAutowiringType($autowiringType); + } } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/DefinitionTest.php b/src/Symfony/Component/DependencyInjection/Tests/DefinitionTest.php index 47288af7686ea..cb6344e49578a 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/DefinitionTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/DefinitionTest.php @@ -408,7 +408,7 @@ public function testTypes() $def = new Definition('stdClass'); $this->assertEquals(array(), $def->getAutowiringTypes()); - $this->assertSame($def, $def->setTypes(array('Foo'))); + $this->assertSame($def, $def->setAutowiringTypes(array('Foo'))); $this->assertEquals(array('Foo'), $def->getAutowiringTypes()); $this->assertSame($def, $def->addAutowiringType('Bar')); $this->assertTrue($def->hasAutowiringType('Bar')); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/bad_types1.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/bad_types1.yml index a9572c4d00a53..891e01497cadf 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/bad_types1.yml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/bad_types1.yml @@ -2,4 +2,4 @@ services: foo_service: class: FooClass # types is not an array - autowiring_types: string + autowiring_types: 1 diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services22.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services22.yml index ed61ad50ac559..55d015baea0fb 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services22.yml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services22.yml @@ -2,3 +2,7 @@ services: foo_service: class: FooClass autowiring_types: [ Foo, Bar ] + + baz_service: + class: Baz + autowiring_types: Foo diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php index 8b1004f1552bb..8ab714e43a2c4 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php @@ -308,6 +308,7 @@ public function testTypes() $loader->load('services22.yml'); $this->assertEquals(array('Foo', 'Bar'), $container->getDefinition('foo_service')->getAutowiringTypes()); + $this->assertEquals(array('Foo'), $container->getDefinition('baz_service')->getAutowiringTypes()); } public function testAutowire() From 936a16a3809bc5a8dddc849c0ff09b389faf93b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Fri, 2 Oct 2015 12:08:24 +0200 Subject: [PATCH 19/19] Typehint against a non-existing class --- .../Compiler/AutowirePass.php | 42 ++++++++++++------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php index 45951ab9df7da..3b85543b8b956 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php @@ -71,31 +71,41 @@ private function completeDefinition($id, Definition $definition) $arguments = $definition->getArguments(); foreach ($constructor->getParameters() as $index => $parameter) { - if (!$typeHint = $parameter->getClass()) { - continue; - } - $argumentExists = array_key_exists($index, $arguments); if ($argumentExists && '' !== $arguments[$index]) { continue; } - if (null === $this->types) { - $this->populateAvailableTypes(); - } + try { + if (!$typeHint = $parameter->getClass()) { + continue; + } - if (isset($this->types[$typeHint->name])) { - $value = new Reference($this->types[$typeHint->name]); - } else { - try { - $value = $this->createAutowiredDefinition($typeHint, $id); - } catch (RuntimeException $e) { - if (!$parameter->isDefaultValueAvailable()) { - throw $e; + if (null === $this->types) { + $this->populateAvailableTypes(); + } + + if (isset($this->types[$typeHint->name])) { + $value = new Reference($this->types[$typeHint->name]); + } else { + try { + $value = $this->createAutowiredDefinition($typeHint, $id); + } catch (RuntimeException $e) { + if (!$parameter->isDefaultValueAvailable()) { + throw $e; + } + + $value = $parameter->getDefaultValue(); } + } + } catch (\ReflectionException $reflectionException) { + // Typehint against a non-existing class - $value = $parameter->getDefaultValue(); + if (!$parameter->isDefaultValueAvailable()) { + continue; } + + $value = $parameter->getDefaultValue(); } if ($argumentExists) {