From 55c6f8f45dd952530ee7a9619994d8b8025a734f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Haso=C5=88?= Date: Mon, 19 Sep 2016 11:26:40 +0200 Subject: [PATCH] [Dependency Injection] Add autowiring types for aliases --- .../Component/DependencyInjection/Alias.php | 72 ++++++++++++++++++- .../Compiler/AutowirePass.php | 7 ++ .../Loader/XmlFileLoader.php | 10 ++- .../Loader/YamlFileLoader.php | 47 ++++++------ .../Tests/Compiler/AutowirePassTest.php | 22 ++++++ .../Tests/Fixtures/xml/services22.xml | 3 + .../Tests/Fixtures/yaml/services22.yml | 4 ++ .../Tests/Loader/XmlFileLoaderTest.php | 1 + .../Tests/Loader/YamlFileLoaderTest.php | 1 + 9 files changed, 144 insertions(+), 23 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Alias.php b/src/Symfony/Component/DependencyInjection/Alias.php index eaf7f00ccd446..dc4a5caefc6dc 100644 --- a/src/Symfony/Component/DependencyInjection/Alias.php +++ b/src/Symfony/Component/DependencyInjection/Alias.php @@ -15,15 +15,17 @@ class Alias { private $id; private $public; + private $autowiringTypes = array(); /** * @param string $id Alias identifier * @param bool $public If this alias is public */ - public function __construct($id, $public = true) + public function __construct($id, $public = true, $autowiringTypes = array()) { $this->id = strtolower($id); $this->public = $public; + $this->setAutowiringTypes($autowiringTypes); } /** @@ -46,6 +48,74 @@ public function setPublic($boolean) $this->public = (bool) $boolean; } + /** + * Gets autowiring types that will default to this alias. + * + * @return string[] + */ + public function getAutowiringTypes() + { + return array_keys($this->autowiringTypes); + } + + /** + * Will this alias default for the given type? + * + * @param string $type + * + * @return bool + */ + public function hasAutowiringType($type) + { + return isset($this->autowiringTypes[$type]); + } + + /** + * Adds a type that will default to this alias. + * + * @param string $type + * + * @return Alias The current instance + */ + public function addAutowiringType($type) + { + $this->autowiringTypes[$type] = true; + + return $this; + } + + /** + * Removes a type. + * + * @param string $type + * + * @return Alias The current instance + */ + public function removeAutowiringType($type) + { + unset($this->autowiringTypes[$type]); + + return $this; + } + + /** + * Sets types that will default to this alias. + * + * @param string[] $types + * + * @return Alias The current instance + */ + public function setAutowiringTypes(array $types) + { + $this->autowiringTypes = array(); + + foreach ($types as $type) { + $this->autowiringTypes[$type] = true; + } + + return $this; + } + /** * Returns the Id of this alias. * diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php index 09cbd4b06c354..ecd926ab72137 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php @@ -218,6 +218,13 @@ private function populateAvailableTypes() foreach ($this->container->getDefinitions() as $id => $definition) { $this->populateAvailableType($id, $definition); } + + foreach ($this->container->getAliases() as $id => $alias) { + foreach ($alias->getAutowiringTypes() as $type) { + $this->definedTypes[$type] = true; + $this->types[$type] = $id; + } + } } /** diff --git a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php index 6b1381b01201d..737132dfce5d6 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php @@ -139,7 +139,13 @@ private function parseDefinition(\DOMElement $service, $file) if ($publicAttr = $service->getAttribute('public')) { $public = XmlUtils::phpize($publicAttr); } - $this->container->setAlias((string) $service->getAttribute('id'), new Alias($alias, $public)); + + $alias = new Alias($alias, $public); + foreach ($this->getChildren($service, 'autowiring-type') as $type) { + $alias->addAutowiringType($type->textContent); + } + + $this->container->setAlias((string) $service->getAttribute('id'), $alias); return; } @@ -510,7 +516,7 @@ private function validateAlias(\DOMElement $alias, $file) } foreach ($alias->childNodes as $child) { - if ($child instanceof \DOMElement && $child->namespaceURI === self::NS) { + if ($child instanceof \DOMElement && $child->namespaceURI === self::NS && $child->tagName !== 'autowiring-type') { @trigger_error(sprintf('Using the element "%s" is deprecated for alias definition "%s" in "%s". The XmlFileLoader will raise an exception in Symfony 4.0, instead of silently ignoring unsupported elements.', $child->localName, $alias->getAttribute('id'), $file), E_USER_DEPRECATED); } } diff --git a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php index 7679a709b8f07..5a792f1d77abe 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php @@ -177,11 +177,11 @@ private function parseDefinition($id, $service, $file) if (isset($service['alias'])) { $public = !array_key_exists('public', $service) || (bool) $service['public']; - $this->container->setAlias($id, new Alias($service['alias'], $public)); + $this->container->setAlias($id, new Alias($service['alias'], $public, $this->parseAutowiringTypes($service, $id, $file))); foreach ($service as $key => $value) { - if (!in_array($key, array('alias', 'public'))) { - @trigger_error(sprintf('The configuration key "%s" is unsupported for alias definition "%s" in "%s". Allowed configuration keys are "alias" and "public". The YamlFileLoader will raise an exception in Symfony 4.0, instead of silently ignoring unsupported attributes.', $key, $id, $file), E_USER_DEPRECATED); + if (!in_array($key, array('alias', 'public', 'autowiring_types'))) { + @trigger_error(sprintf('The configuration key "%s" is unsupported for alias definition "%s" in "%s". Allowed configuration keys are "alias", "public" and "autowiring_types". The YamlFileLoader will raise an exception in Symfony 4.0, instead of silently ignoring unsupported attributes.', $key, $id, $file), E_USER_DEPRECATED); } } @@ -305,23 +305,7 @@ private function parseDefinition($id, $service, $file) $definition->setAutowired($service['autowire']); } - if (isset($service['autowiring_types'])) { - 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)); - } - - 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); - } - } - } + $definition->setAutowiringTypes($this->parseAutowiringTypes($service, $id, $file)); $this->container->setDefinition($id, $definition); } @@ -501,6 +485,29 @@ private function loadFromExtensions($content) } } + private function parseAutowiringTypes(array $service, $id, $file) + { + if (!isset($service['autowiring_types'])) { + return array(); + } + + if (is_string($service['autowiring_types'])) { + return array($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)); + } + + 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)); + } + } + + return $service['autowiring_types']; + } + } + /** * Checks the keywords used to define a service. * diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php index 684e99b63228f..4a56f92dcc1c7 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php @@ -535,6 +535,28 @@ public function testSetterInjectionCollisionThrowsException() $pass = new AutowirePass(); $pass->process($container); } + + public function testAutowiringTypesAliasDefinition() + { + $container = new ContainerBuilder(); + + $container->register('a.default', __NAMESPACE__.'\A'); + $container->register('a.extra', __NAMESPACE__.'\B'); + $container->register('c', __NAMESPACE__.'\C')->setAutowired(true); + $container->setAlias('a', 'a.extra'); + + $container->getAlias('a')->addAutowiringType(__NAMESPACE__.'\A'); + + $pass = new AutowirePass(); + $pass->process($container); + + $this->assertEquals( + array( + new Reference('a'), + ), + $container->getDefinition('c')->getArguments() + ); + } } class Foo diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services22.xml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services22.xml index fa79d389489fb..47d23557ee979 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services22.xml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services22.xml @@ -5,5 +5,8 @@ Bar Baz + + Router + diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services22.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services22.yml index 55d015baea0fb..b062de7cbe9fa 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services22.yml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services22.yml @@ -6,3 +6,7 @@ services: baz_service: class: Baz autowiring_types: Foo + + router: + alias: router.default + autowiring_types: Router diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php index a351c62ebc881..f4a0943fb367a 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php @@ -545,6 +545,7 @@ public function testType() $loader->load('services22.xml'); $this->assertEquals(array('Bar', 'Baz'), $container->getDefinition('foo')->getAutowiringTypes()); + $this->assertEquals(array('Router'), $container->getAlias('router')->getAutowiringTypes()); } public function testAutowire() diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php index 13308a94a014a..1ea385e2b4ca1 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php @@ -314,6 +314,7 @@ public function testTypes() $this->assertEquals(array('Foo', 'Bar'), $container->getDefinition('foo_service')->getAutowiringTypes()); $this->assertEquals(array('Foo'), $container->getDefinition('baz_service')->getAutowiringTypes()); + $this->assertEquals(array('Router'), $container->getAlias('router')->getAutowiringTypes()); } public function testAutowire()