From cc5e582dcf86819ab034dcdfb5ce73f299a8aa08 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 4 Apr 2017 19:35:51 +0200 Subject: [PATCH] [BC BREAK][DI] Always autowire "by id" instead of using reflection against all existing services --- UPGRADE-3.3.md | 2 + UPGRADE-4.0.md | 2 + .../Console/Descriptor/JsonDescriptor.php | 2 +- .../Console/Descriptor/MarkdownDescriptor.php | 2 +- .../Console/Descriptor/TextDescriptor.php | 2 +- .../Console/Descriptor/XmlDescriptor.php | 2 +- .../DependencyInjection/CHANGELOG.md | 2 + .../Compiler/AutowirePass.php | 121 +++----- .../RegisterServiceSubscribersPass.php | 7 +- .../ResolveDefinitionTemplatesPass.php | 4 +- .../Compiler/ServiceLocatorTagPass.php | 4 +- .../DependencyInjection/Definition.php | 24 +- .../DependencyInjection/Dumper/PhpDumper.php | 3 +- .../DependencyInjection/Dumper/XmlDumper.php | 2 +- .../DependencyInjection/Dumper/YamlDumper.php | 2 +- .../Loader/XmlFileLoader.php | 21 +- .../Loader/YamlFileLoader.php | 8 - .../schema/dic/services/services-1.0.xsd | 14 +- .../Tests/Compiler/AutowirePassTest.php | 291 ++++++++---------- .../RegisterServiceSubscribersPassTest.php | 2 - .../Tests/ContainerBuilderTest.php | 4 +- .../Tests/Fixtures/php/services24.php | 2 +- .../Fixtures/php/services_subscriber.php | 4 +- .../Tests/Fixtures/xml/services24.xml | 2 +- .../Tests/Fixtures/yaml/services24.yml | 2 +- ...RegisterControllerArgumentLocatorsPass.php | 3 +- .../FragmentRendererPassTest.php | 9 +- ...sterControllerArgumentLocatorsPassTest.php | 7 +- ...mptyControllerArgumentLocatorsPassTest.php | 7 +- 29 files changed, 212 insertions(+), 345 deletions(-) diff --git a/UPGRADE-3.3.md b/UPGRADE-3.3.md index d58a018f2bb03..f068e4f4322f5 100644 --- a/UPGRADE-3.3.md +++ b/UPGRADE-3.3.md @@ -80,6 +80,8 @@ Debug DependencyInjection ------------------- + * [BC BREAK] autowiring now happens only when a type-hint matches its corresponding FQCN id or alias. Please follow the suggestions provided by the exceptions thrown at compilation to upgrade your service configuration. + * [BC BREAK] `_defaults` and `_instanceof` are now reserved service names in Yaml configurations. Please rename any services with that names. * [BC BREAK] non-numeric keys in methods and constructors arguments have never been supported and are now forbidden. Please remove them if you happen to have one. diff --git a/UPGRADE-4.0.md b/UPGRADE-4.0.md index b9bf1295ee8e5..401f3ae736005 100644 --- a/UPGRADE-4.0.md +++ b/UPGRADE-4.0.md @@ -73,6 +73,8 @@ Debug DependencyInjection ------------------- + * Autowiring now happens only when a type-hint matches its corresponding FQCN id or alias. + * `_defaults` and `_instanceof` are now reserved service names in Yaml configurations. Please rename any services with that names. * Non-numeric keys in methods and constructors arguments have never been supported and are now forbidden. Please remove them if you happen to have one. diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php index bee019a0badef..81d7233811f1b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php @@ -221,7 +221,7 @@ private function getContainerDefinitionData(Definition $definition, $omitTags = 'lazy' => $definition->isLazy(), 'shared' => $definition->isShared(), 'abstract' => $definition->isAbstract(), - 'autowire' => $definition->isAutowired() ? (Definition::AUTOWIRE_BY_TYPE === $definition->getAutowired() ? 'by-type' : 'by-id') : false, + 'autowire' => $definition->isAutowired(), ); foreach ($definition->getAutowiringTypes(false) as $autowiringType) { diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php index 6b1d7a9921b87..c0319aad6bb19 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php @@ -182,7 +182,7 @@ protected function describeContainerDefinition(Definition $definition, array $op ."\n".'- Lazy: '.($definition->isLazy() ? 'yes' : 'no') ."\n".'- Shared: '.($definition->isShared() ? 'yes' : 'no') ."\n".'- Abstract: '.($definition->isAbstract() ? 'yes' : 'no') - ."\n".'- Autowired: '.($definition->isAutowired() ? (Definition::AUTOWIRE_BY_TYPE === $definition->getAutowired() ? 'by-type' : 'by-id') : 'no') + ."\n".'- Autowired: '.($definition->isAutowired() ? 'yes' : 'no') ; foreach ($definition->getAutowiringTypes(false) as $autowiringType) { diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php index 7b2e01f85171a..2481b15375801 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php @@ -295,7 +295,7 @@ protected function describeContainerDefinition(Definition $definition, array $op $tableRows[] = array('Lazy', $definition->isLazy() ? 'yes' : 'no'); $tableRows[] = array('Shared', $definition->isShared() ? 'yes' : 'no'); $tableRows[] = array('Abstract', $definition->isAbstract() ? 'yes' : 'no'); - $tableRows[] = array('Autowired', $definition->isAutowired() ? (Definition::AUTOWIRE_BY_TYPE === $definition->getAutowired() ? 'by-type' : 'by-id') : 'no'); + $tableRows[] = array('Autowired', $definition->isAutowired() ? 'yes' : 'no'); if ($autowiringTypes = $definition->getAutowiringTypes(false)) { $tableRows[] = array('Autowiring Types', implode(', ', $autowiringTypes)); diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php index d930c4a64615c..40e749aa6a3e7 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php @@ -371,7 +371,7 @@ private function getContainerDefinitionDocument(Definition $definition, $id = nu $serviceXML->setAttribute('lazy', $definition->isLazy() ? 'true' : 'false'); $serviceXML->setAttribute('shared', $definition->isShared() ? 'true' : 'false'); $serviceXML->setAttribute('abstract', $definition->isAbstract() ? 'true' : 'false'); - $serviceXML->setAttribute('autowired', $definition->isAutowired() ? (Definition::AUTOWIRE_BY_TYPE === $definition->getAutowired() ? 'by-type' : 'by-id') : 'false'); + $serviceXML->setAttribute('autowired', $definition->isAutowired() ? 'true' : 'false'); $serviceXML->setAttribute('file', $definition->getFile()); $calls = $definition->getMethodCalls(); diff --git a/src/Symfony/Component/DependencyInjection/CHANGELOG.md b/src/Symfony/Component/DependencyInjection/CHANGELOG.md index b28bb6e84ae66..a9a382c9060ba 100644 --- a/src/Symfony/Component/DependencyInjection/CHANGELOG.md +++ b/src/Symfony/Component/DependencyInjection/CHANGELOG.md @@ -4,6 +4,8 @@ CHANGELOG 3.3.0 ----- + * [BC BREAK] autowiring now happens only when a type-hint matches its corresponding FQCN id or alias. + Please follow the suggestions provided by the exceptions thrown at compilation to upgrade your service configuration. * added "ServiceSubscriberInterface" - to allow for per-class explicit service-locator definitions * added "container.service_locator" tag for defining service-locator services * added anonymous services support in YAML configuration files using the `!service` tag. diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php index b84becb7505ed..35449b35677df 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php @@ -31,7 +31,6 @@ class AutowirePass extends AbstractRecursivePass private $types; private $ambiguousServiceTypes = array(); private $autowired = array(); - private $currentDefinition; /** * {@inheritdoc} @@ -77,7 +76,7 @@ public static function createResourceForClass(\ReflectionClass $reflectionClass) */ protected function processValue($value, $isRoot = false) { - if ($value instanceof TypedReference && $this->currentDefinition->isAutowired() && !$this->container->has((string) $value)) { + if ($value instanceof TypedReference && !$this->container->has((string) $value)) { if ($ref = $this->getAutowiredReference($value->getType(), $value->canBeAutoregistered())) { $value = new TypedReference((string) $ref, $value->getType(), $value->getInvalidBehavior(), $value->canBeAutoregistered()); } else { @@ -87,45 +86,37 @@ protected function processValue($value, $isRoot = false) if (!$value instanceof Definition) { return parent::processValue($value, $isRoot); } + if (!$value->isAutowired() || $value->isAbstract() || !$value->getClass()) { + return parent::processValue($value, $isRoot); + } + if (!$reflectionClass = $this->container->getReflectionClass($value->getClass())) { + $this->container->log($this, sprintf('Skipping service "%s": Class or interface "%s" does not exist.', $this->currentId, $value->getClass())); - $parentDefinition = $this->currentDefinition; - $this->currentDefinition = $value; - - try { - if (!$value->isAutowired() || $value->isAbstract() || !$value->getClass()) { - return parent::processValue($value, $isRoot); - } - if (!$reflectionClass = $this->container->getReflectionClass($value->getClass())) { - $this->container->log($this, sprintf('Skipping service "%s": Class or interface "%s" does not exist.', $this->currentId, $value->getClass())); - - return parent::processValue($value, $isRoot); - } - - $autowiredMethods = $this->getMethodsToAutowire($reflectionClass); - $methodCalls = $value->getMethodCalls(); + return parent::processValue($value, $isRoot); + } - if ($constructor = $this->getConstructor($value, false)) { - array_unshift($methodCalls, array($constructor, $value->getArguments())); - } + $autowiredMethods = $this->getMethodsToAutowire($reflectionClass); + $methodCalls = $value->getMethodCalls(); - $methodCalls = $this->autowireCalls($reflectionClass, $methodCalls, $autowiredMethods); + if ($constructor = $this->getConstructor($value, false)) { + array_unshift($methodCalls, array($constructor, $value->getArguments())); + } - if ($constructor) { - list(, $arguments) = array_shift($methodCalls); + $methodCalls = $this->autowireCalls($reflectionClass, $methodCalls, $autowiredMethods); - if ($arguments !== $value->getArguments()) { - $value->setArguments($arguments); - } - } + if ($constructor) { + list(, $arguments) = array_shift($methodCalls); - if ($methodCalls !== $value->getMethodCalls()) { - $value->setMethodCalls($methodCalls); + if ($arguments !== $value->getArguments()) { + $value->setArguments($arguments); } + } - return parent::processValue($value, $isRoot); - } finally { - $this->currentDefinition = $parentDefinition; + if ($methodCalls !== $value->getMethodCalls()) { + $value->setMethodCalls($methodCalls); } + + return parent::processValue($value, $isRoot); } /** @@ -186,7 +177,7 @@ private function autowireCalls(\ReflectionClass $reflectionClass, array $methodC $reflectionMethod = $autowiredMethods[$lcMethod]; unset($autowiredMethods[$lcMethod]); } else { - $reflectionMethod = $this->getReflectionMethod($this->currentDefinition, $method); + $reflectionMethod = $this->getReflectionMethod(new Definition($reflectionClass->name), $method); } $arguments = $this->autowireMethod($reflectionMethod, $arguments); @@ -242,7 +233,7 @@ private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, a // no default value? Then fail if (!$parameter->isDefaultValueAvailable()) { - throw new RuntimeException(sprintf('Cannot autowire service "%s": argument $%s of method %s() must have a type-hint or be given a value explicitly.', $this->currentId, $parameter->name, $class !== $this->currentId ? $class.'::'.$method : $method)); + throw new RuntimeException(sprintf('Cannot autowire service "%s": argument "$%s" of method "%s()" must have a type-hint or be given a value explicitly.', $this->currentId, $parameter->name, $class !== $this->currentId ? $class.'::'.$method : $method)); } // specifically pass the default value @@ -251,8 +242,8 @@ private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, a continue; } - if (!$value = $this->getAutowiredReference($type)) { - $failureMessage = $this->createTypeNotFoundMessage($type, sprintf('argument $%s of method %s()', $parameter->name, $class !== $this->currentId ? $class.'::'.$method : $method)); + if (!$value = $this->getAutowiredReference($type, !$parameter->isOptional())) { + $failureMessage = $this->createTypeNotFoundMessage($type, sprintf('argument "$%s" of method "%s()"', $parameter->name, $class !== $this->currentId ? $class.'::'.$method : $method)); if ($parameter->isDefaultValueAvailable()) { $value = $parameter->getDefaultValue(); @@ -286,19 +277,13 @@ private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, a /** * @return Reference|null A reference to the service matching the given type, if any - * - * @throws RuntimeException */ - private function getAutowiredReference($type, $autoRegister = true) + private function getAutowiredReference($type, $autoRegister) { if ($this->container->has($type) && !$this->container->findDefinition($type)->isAbstract()) { return new Reference($type); } - if (Definition::AUTOWIRE_BY_ID === $this->currentDefinition->getAutowired()) { - return; - } - if (isset($this->autowired[$type])) { return $this->autowired[$type] ? new Reference($this->autowired[$type]) : null; } @@ -307,19 +292,11 @@ private function getAutowiredReference($type, $autoRegister = true) $this->populateAvailableTypes(); } - if (isset($this->types[$type])) { - $this->container->log($this, sprintf('Service "%s" matches type "%s" and has been autowired into service "%s".', $this->types[$type], $type, $this->currentId)); - + if (isset($this->definedTypes[$type])) { return new Reference($this->types[$type]); } - if (isset($this->ambiguousServiceTypes[$type])) { - $classOrInterface = class_exists($type, false) ? 'class' : 'interface'; - - throw new RuntimeException(sprintf('Cannot autowire service "%s": multiple candidate services exist for %s "%s".%s', $this->currentId, $classOrInterface, $type, $this->createTypeAlternatives($type))); - } - - if ($autoRegister) { + if ($autoRegister && !isset($this->types[$type]) && !isset($this->ambiguousServiceTypes[$type])) { return $this->createAutowiredDefinition($type); } } @@ -355,22 +332,8 @@ private function populateAvailableType($id, Definition $definition) unset($this->ambiguousServiceTypes[$type]); } - if ($deprecated = $definition->isDeprecated()) { - $prevErrorHandler = set_error_handler(function ($level, $message, $file, $line) use (&$prevErrorHandler) { - return (E_USER_DEPRECATED === $level || !$prevErrorHandler) ? false : $prevErrorHandler($level, $message, $file, $line); - }); - } - - $e = null; - - try { - if (!$reflectionClass = $this->container->getReflectionClass($definition->getClass(), true)) { - return; - } - } finally { - if ($deprecated) { - restore_error_handler(); - } + if ($definition->isDeprecated() || !$reflectionClass = $this->container->getReflectionClass($definition->getClass(), true)) { + return; } foreach ($reflectionClass->getInterfaces() as $reflectionInterface) { @@ -429,10 +392,9 @@ private function createAutowiredDefinition($type) return; } - $currentDefinition = $this->currentDefinition; $currentId = $this->currentId; $this->currentId = $this->autowired[$type] = $argumentId = sprintf('autowired.%s', $type); - $this->currentDefinition = $argumentDefinition = new Definition($type); + $argumentDefinition = new Definition($type); $argumentDefinition->setPublic(false); $argumentDefinition->setAutowired(true); @@ -446,7 +408,6 @@ private function createAutowiredDefinition($type) return; } finally { $this->currentId = $currentId; - $this->currentDefinition = $currentDefinition; } $this->container->log($this, sprintf('Type "%s" has been auto-registered for service "%s".', $type, $this->currentId)); @@ -456,20 +417,14 @@ private function createAutowiredDefinition($type) private function createTypeNotFoundMessage($type, $label) { - $autowireById = Definition::AUTOWIRE_BY_ID === $this->currentDefinition->getAutowired(); - if (!$classOrInterface = class_exists($type, $autowireById) ? 'class' : (interface_exists($type, false) ? 'interface' : null)) { - return sprintf('Cannot autowire service "%s": %s has type "%s" but this class does not exist.', $this->currentId, $label, $type); - } - if (null === $this->types) { - $this->populateAvailableTypes(); - } - if ($autowireById) { - $message = sprintf('%s references %s "%s" but no such service exists.%s', $label, $classOrInterface, $type, $this->createTypeAlternatives($type)); + if (!$r = $this->container->getReflectionClass($type, true)) { + $message = sprintf('has type "%s" but this class does not exist.', $type); } else { - $message = sprintf('no services were found matching the "%s" %s and it cannot be auto-registered for %s.', $type, $classOrInterface, $label); + $message = $this->container->has($type) ? 'this service is abstract' : 'no such service exists'; + $message = sprintf('references %s "%s" but %s.%s', $r->isInterface() ? 'interface' : 'class', $type, $message, $this->createTypeAlternatives($type)); } - return sprintf('Cannot autowire service "%s": %s', $this->currentId, $message); + return sprintf('Cannot autowire service "%s": %s %s', $this->currentId, $label, $message); } private function createTypeAlternatives($type) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/RegisterServiceSubscribersPass.php b/src/Symfony/Component/DependencyInjection/Compiler/RegisterServiceSubscribersPass.php index 281410b77c280..a02265afe1e10 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/RegisterServiceSubscribersPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/RegisterServiceSubscribersPass.php @@ -38,9 +38,11 @@ protected function processValue($value, $isRoot = false) } $serviceMap = array(); + $autowire = $value->isAutowired(); foreach ($value->getTag('container.service_subscriber') as $attributes) { if (!$attributes) { + $autowire = true; continue; } ksort($attributes); @@ -82,6 +84,9 @@ protected function processValue($value, $isRoot = false) $key = $type; } if (!isset($serviceMap[$key])) { + if (!$autowire) { + throw new InvalidArgumentException(sprintf('Service "%s" misses a "container.service_subscriber" tag with "key"/"id" attributes corresponding to entry "%s" as returned by %s::getSubscribedServices().', $this->currentId, $key, $class)); + } $serviceMap[$key] = new Reference($type); } @@ -95,7 +100,7 @@ protected function processValue($value, $isRoot = false) } $serviceLocator = $this->serviceLocator; - $this->serviceLocator = (string) ServiceLocatorTagPass::register($this->container, $subscriberMap, $value->getAutowired()); + $this->serviceLocator = (string) ServiceLocatorTagPass::register($this->container, $subscriberMap); try { return parent::processValue($value); diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ResolveDefinitionTemplatesPass.php b/src/Symfony/Component/DependencyInjection/Compiler/ResolveDefinitionTemplatesPass.php index 9cc22502cc6e2..7d9f7da4b8452 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/ResolveDefinitionTemplatesPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/ResolveDefinitionTemplatesPass.php @@ -100,7 +100,7 @@ private function doResolveDefinition(ChildDefinition $definition) $def->setFile($parentDef->getFile()); $def->setPublic($parentDef->isPublic()); $def->setLazy($parentDef->isLazy()); - $def->setAutowired($parentDef->getAutowired()); + $def->setAutowired($parentDef->isAutowired()); self::mergeDefinition($def, $definition); @@ -146,7 +146,7 @@ public static function mergeDefinition(Definition $def, ChildDefinition $definit $def->setDeprecated($definition->isDeprecated(), $definition->getDeprecationMessage('%service_id%')); } if (isset($changes['autowired'])) { - $def->setAutowired($definition->getAutowired()); + $def->setAutowired($definition->isAutowired()); } if (isset($changes['decorated_service'])) { $decoratedService = $definition->getDecoratedService(); diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ServiceLocatorTagPass.php b/src/Symfony/Component/DependencyInjection/Compiler/ServiceLocatorTagPass.php index 8bac873e63bbb..bf9f83bbe80d0 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/ServiceLocatorTagPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/ServiceLocatorTagPass.php @@ -75,11 +75,10 @@ protected function processValue($value, $isRoot = false) /** * @param ContainerBuilder $container * @param Reference[] $refMap - * @param int|bool $autowired * * @return Reference */ - public static function register(ContainerBuilder $container, array $refMap, $autowired = false) + public static function register(ContainerBuilder $container, array $refMap) { foreach ($refMap as $id => $ref) { $refMap[$id] = new ServiceClosureArgument($ref); @@ -89,7 +88,6 @@ public static function register(ContainerBuilder $container, array $refMap, $aut $locator = (new Definition(ServiceLocator::class)) ->addArgument($refMap) ->setPublic(false) - ->setAutowired($autowired) ->addTag('container.service_locator'); if (!$container->has($id = 'service_locator.'.md5(serialize($locator)))) { diff --git a/src/Symfony/Component/DependencyInjection/Definition.php b/src/Symfony/Component/DependencyInjection/Definition.php index e06d996a867aa..e3c79c511aa7a 100644 --- a/src/Symfony/Component/DependencyInjection/Definition.php +++ b/src/Symfony/Component/DependencyInjection/Definition.php @@ -21,9 +21,6 @@ */ class Definition { - const AUTOWIRE_BY_TYPE = 1; - const AUTOWIRE_BY_ID = 2; - private $class; private $file; private $factory; @@ -40,7 +37,7 @@ class Definition private $abstract = false; private $lazy = false; private $decoratedService; - private $autowired = 0; + private $autowired = false; private $autowiringTypes = array(); protected $arguments; @@ -699,16 +696,6 @@ public function setAutowiringTypes(array $types) * @return bool */ public function isAutowired() - { - return (bool) $this->autowired; - } - - /** - * Gets the autowiring mode. - * - * @return int - */ - public function getAutowired() { return $this->autowired; } @@ -716,18 +703,13 @@ public function getAutowired() /** * Sets autowired. * - * @param bool|int $autowired + * @param bool $autowired * * @return $this */ public function setAutowired($autowired) { - $autowired = (int) $autowired; - - if ($autowired && self::AUTOWIRE_BY_TYPE !== $autowired && self::AUTOWIRE_BY_ID !== $autowired) { - throw new InvalidArgumentException(sprintf('Invalid argument: Definition::AUTOWIRE_BY_TYPE (%d) or Definition::AUTOWIRE_BY_ID (%d) expected, %d given.', self::AUTOWIRE_BY_TYPE, self::AUTOWIRE_BY_ID, $autowired)); - } - $this->autowired = $autowired; + $this->autowired = (bool) $autowired; return $this; } diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php index 0657e8c85298b..9b298f8c7a00f 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php @@ -646,11 +646,10 @@ private function addService($id, Definition $definition) } if ($definition->isAutowired()) { - $autowired = Definition::AUTOWIRE_BY_TYPE === $definition->getAutowired() ? 'types' : 'ids'; $doc .= <<isAutowired()) { - $service->setAttribute('autowire', Definition::AUTOWIRE_BY_TYPE === $definition->getAutowired() ? 'by-type' : 'by-id'); + $service->setAttribute('autowire', 'true'); } foreach ($definition->getAutowiringTypes(false) as $autowiringTypeValue) { diff --git a/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php index 6fc8e1c3a3553..81951fe536699 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php @@ -106,7 +106,7 @@ private function addService($id, $definition) } if ($definition->isAutowired()) { - $code .= sprintf(" autowire: %s\n", Definition::AUTOWIRE_BY_TYPE === $definition->getAutowired() ? 'by_type' : 'by_id'); + $code .= " autowire: true\n"; } $autowiringTypesCode = ''; diff --git a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php index ae02e088d23b2..798b6b1adcde4 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php @@ -172,7 +172,7 @@ private function getServiceDefaults(\DOMDocument $xml, $file) } } if ($defaultsNode->hasAttribute('autowire')) { - $defaults['autowire'] = $this->getAutowired($defaultsNode->getAttribute('autowire'), $file); + $defaults['autowire'] = XmlUtils::phpize($defaultsNode->getAttribute('autowire')); } if ($defaultsNode->hasAttribute('public')) { $defaults['public'] = XmlUtils::phpize($defaultsNode->getAttribute('public')); @@ -238,7 +238,7 @@ private function parseDefinition(\DOMElement $service, $file, array $defaults = } if ($value = $service->getAttribute('autowire')) { - $definition->setAutowired($this->getAutowired($value, $file)); + $definition->setAutowired(XmlUtils::phpize($value)); } elseif (isset($defaults['autowire'])) { $definition->setAutowired($defaults['autowire']); } @@ -656,23 +656,6 @@ private function loadFromExtensions(\DOMDocument $xml) } } - private function getAutowired($value, $file) - { - if (is_bool($value = XmlUtils::phpize($value))) { - return $value; - } - - if ('by-type' === $value) { - return Definition::AUTOWIRE_BY_TYPE; - } - - if ('by-id' === $value) { - return Definition::AUTOWIRE_BY_ID; - } - - throw new InvalidArgumentException(sprintf('Invalid autowire attribute: "by-type", "by-id", "true" or "false" expected, "%s" given in "%s".', $value, $file)); - } - /** * Converts a \DomElement object to a PHP array. * diff --git a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php index 8c4df2ed75e54..7c7550e6c982b 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php @@ -486,14 +486,6 @@ private function parseDefinition($id, $service, $file, array $defaults) $autowire = isset($service['autowire']) ? $service['autowire'] : (isset($defaults['autowire']) ? $defaults['autowire'] : null); if (null !== $autowire) { - if ('by_type' === $autowire) { - $autowire = Definition::AUTOWIRE_BY_TYPE; - } elseif ('by_id' === $autowire) { - $autowire = Definition::AUTOWIRE_BY_ID; - } elseif (!is_bool($autowire)) { - throw new InvalidArgumentException(sprintf('Invalid autowire attribute: "by_type", "by_id", true or false expected, "%s" given in "%s".', is_string($autowire) ? $autowire : gettype($autowire), $file)); - } - $definition->setAutowired($autowire); } 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 1a242d2134bc7..ebbcf00ef487a 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 @@ -102,7 +102,7 @@ - + @@ -130,7 +130,7 @@ - + @@ -149,7 +149,7 @@ - + @@ -169,7 +169,7 @@ - + @@ -263,10 +263,4 @@ - - - - - - diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php index 687f56ff745d0..f962e58f500ca 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php @@ -13,8 +13,8 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\DependencyInjection\Compiler\AutowirePass; +use Symfony\Component\DependencyInjection\Compiler\ResolveClassPass; use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Exception\RuntimeException; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\Tests\Fixtures\includes\FooVariadic; @@ -29,15 +29,15 @@ public function testProcess() { $container = new ContainerBuilder(); - $container->register('foo', __NAMESPACE__.'\Foo'); + $container->register(Foo::class); $barDefinition = $container->register('bar', __NAMESPACE__.'\Bar'); $barDefinition->setAutowired(true); - $pass = new AutowirePass(); - $pass->process($container); + (new ResolveClassPass())->process($container); + (new AutowirePass())->process($container); $this->assertCount(1, $container->getDefinition('bar')->getArguments()); - $this->assertEquals('foo', (string) $container->getDefinition('bar')->getArgument(0)); + $this->assertEquals(Foo::class, (string) $container->getDefinition('bar')->getArgument(0)); } /** @@ -46,47 +46,55 @@ public function testProcess() public function testProcessVariadic() { $container = new ContainerBuilder(); - $container->register('foo', Foo::class); + $container->register(Foo::class); $definition = $container->register('fooVariadic', FooVariadic::class); $definition->setAutowired(true); - $pass = new AutowirePass(); - $pass->process($container); + (new ResolveClassPass())->process($container); + (new AutowirePass())->process($container); $this->assertCount(1, $container->getDefinition('fooVariadic')->getArguments()); - $this->assertEquals('foo', (string) $container->getDefinition('fooVariadic')->getArgument(0)); + $this->assertEquals(Foo::class, (string) $container->getDefinition('fooVariadic')->getArgument(0)); } + /** + * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException + * @expectedExceptionMessage Cannot autowire service "c": argument "$a" of method "Symfony\Component\DependencyInjection\Tests\Compiler\C::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\A" but no such service exists. This type-hint could be aliased to the existing "Symfony\Component\DependencyInjection\Tests\Compiler\B" service. + */ public function testProcessAutowireParent() { $container = new ContainerBuilder(); - $container->register('b', __NAMESPACE__.'\B'); + $container->register(B::class); $cDefinition = $container->register('c', __NAMESPACE__.'\C'); $cDefinition->setAutowired(true); - $pass = new AutowirePass(); - $pass->process($container); + (new ResolveClassPass())->process($container); + (new AutowirePass())->process($container); $this->assertCount(1, $container->getDefinition('c')->getArguments()); - $this->assertEquals('b', (string) $container->getDefinition('c')->getArgument(0)); + $this->assertEquals(B::class, (string) $container->getDefinition('c')->getArgument(0)); } + /** + * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException + * @expectedExceptionMessage Cannot autowire service "g": argument "$d" of method "Symfony\Component\DependencyInjection\Tests\Compiler\G::__construct()" references interface "Symfony\Component\DependencyInjection\Tests\Compiler\DInterface" but no such service exists. This type-hint could be aliased to the existing "Symfony\Component\DependencyInjection\Tests\Compiler\F" service. + */ public function testProcessAutowireInterface() { $container = new ContainerBuilder(); - $container->register('f', __NAMESPACE__.'\F'); + $container->register(F::class); $gDefinition = $container->register('g', __NAMESPACE__.'\G'); $gDefinition->setAutowired(true); - $pass = new AutowirePass(); - $pass->process($container); + (new ResolveClassPass())->process($container); + (new AutowirePass())->process($container); $this->assertCount(3, $container->getDefinition('g')->getArguments()); - $this->assertEquals('f', (string) $container->getDefinition('g')->getArgument(0)); - $this->assertEquals('f', (string) $container->getDefinition('g')->getArgument(1)); - $this->assertEquals('f', (string) $container->getDefinition('g')->getArgument(2)); + $this->assertEquals(F::class, (string) $container->getDefinition('g')->getArgument(0)); + $this->assertEquals(F::class, (string) $container->getDefinition('g')->getArgument(1)); + $this->assertEquals(F::class, (string) $container->getDefinition('g')->getArgument(2)); } public function testCompleteExistingDefinition() @@ -94,38 +102,38 @@ public function testCompleteExistingDefinition() $container = new ContainerBuilder(); $container->register('b', __NAMESPACE__.'\B'); - $container->register('f', __NAMESPACE__.'\F'); + $container->register(DInterface::class, F::class); $hDefinition = $container->register('h', __NAMESPACE__.'\H')->addArgument(new Reference('b')); $hDefinition->setAutowired(true); - $pass = new AutowirePass(); - $pass->process($container); + (new ResolveClassPass())->process($container); + (new AutowirePass())->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)); + $this->assertEquals(DInterface::class, (string) $container->getDefinition('h')->getArgument(1)); } public function testCompleteExistingDefinitionWithNotDefinedArguments() { $container = new ContainerBuilder(); - $container->register('b', __NAMESPACE__.'\B'); - $container->register('f', __NAMESPACE__.'\F'); + $container->register(B::class); + $container->register(DInterface::class, F::class); $hDefinition = $container->register('h', __NAMESPACE__.'\H')->addArgument('')->addArgument(''); $hDefinition->setAutowired(true); - $pass = new AutowirePass(); - $pass->process($container); + (new ResolveClassPass())->process($container); + (new AutowirePass())->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)); + $this->assertEquals(B::class, (string) $container->getDefinition('h')->getArgument(0)); + $this->assertEquals(DInterface::class, (string) $container->getDefinition('h')->getArgument(1)); } /** * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException - * @expectedExceptionMessage Cannot autowire service "a": multiple candidate services exist for interface "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface". This type-hint could be aliased to one of these existing services: "c1", "c2", "c3". + * @expectedExceptionMessage Cannot autowire service "a": argument "$collision" of method "Symfony\Component\DependencyInjection\Tests\Compiler\CannotBeAutowired::__construct()" references interface "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" but no such service exists. This type-hint could be aliased to one of these existing services: "c1", "c2", "c3". */ public function testTypeCollision() { @@ -143,7 +151,7 @@ public function testTypeCollision() /** * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException - * @expectedExceptionMessage Cannot autowire service "a": multiple candidate services exist for class "Symfony\Component\DependencyInjection\Tests\Compiler\Foo". This type-hint could be aliased to one of these existing services: "a1", "a2". + * @expectedExceptionMessage Cannot autowire service "a": argument "$k" of method "Symfony\Component\DependencyInjection\Tests\Compiler\NotGuessableArgument::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\Foo" but no such service exists. This type-hint could be aliased to one of these existing services: "a1", "a2". */ public function testTypeNotGuessable() { @@ -160,7 +168,7 @@ public function testTypeNotGuessable() /** * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException - * @expectedExceptionMessage Cannot autowire service "a": multiple candidate services exist for class "Symfony\Component\DependencyInjection\Tests\Compiler\A". This type-hint could be aliased to one of these existing services: "a1", "a2". + * @expectedExceptionMessage Cannot autowire service "a": argument "$k" of method "Symfony\Component\DependencyInjection\Tests\Compiler\NotGuessableArgumentForSubclass::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\A" but no such service exists. This type-hint could be aliased to one of these existing services: "a1", "a2". */ public function testTypeNotGuessableWithSubclass() { @@ -177,7 +185,7 @@ public function testTypeNotGuessableWithSubclass() /** * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException - * @expectedExceptionMessage Cannot autowire service "a": no services were found matching the "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" interface and it cannot be auto-registered for argument $collision of method Symfony\Component\DependencyInjection\Tests\Compiler\CannotBeAutowired::__construct(). + * @expectedExceptionMessage Cannot autowire service "a": argument "$collision" of method "Symfony\Component\DependencyInjection\Tests\Compiler\CannotBeAutowired::__construct()" references interface "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" but no such service exists. */ public function testTypeNotGuessableNoServicesFound() { @@ -251,51 +259,51 @@ public function testResolveParameter() { $container = new ContainerBuilder(); - $container->setParameter('class_name', __NAMESPACE__.'\Foo'); - $container->register('foo', '%class_name%'); - $barDefinition = $container->register('bar', __NAMESPACE__.'\Bar'); + $container->setParameter('class_name', Bar::class); + $container->register(Foo::class); + $barDefinition = $container->register('bar', '%class_name%'); $barDefinition->setAutowired(true); - $pass = new AutowirePass(); - $pass->process($container); + (new ResolveClassPass())->process($container); + (new AutowirePass())->process($container); - $this->assertEquals('foo', $container->getDefinition('bar')->getArgument(0)); + $this->assertEquals(Foo::class, $container->getDefinition('bar')->getArgument(0)); } public function testOptionalParameter() { $container = new ContainerBuilder(); - $container->register('a', __NAMESPACE__.'\A'); - $container->register('foo', __NAMESPACE__.'\Foo'); + $container->register(A::class); + $container->register(Foo::class); $optDefinition = $container->register('opt', __NAMESPACE__.'\OptionalParameter'); $optDefinition->setAutowired(true); - $pass = new AutowirePass(); - $pass->process($container); + (new ResolveClassPass())->process($container); + (new AutowirePass())->process($container); $definition = $container->getDefinition('opt'); $this->assertNull($definition->getArgument(0)); - $this->assertEquals('a', $definition->getArgument(1)); - $this->assertEquals('foo', $definition->getArgument(2)); + $this->assertEquals(A::class, $definition->getArgument(1)); + $this->assertEquals(Foo::class, $definition->getArgument(2)); } public function testDontTriggerAutowiring() { $container = new ContainerBuilder(); - $container->register('foo', __NAMESPACE__.'\Foo'); + $container->register(Foo::class); $container->register('bar', __NAMESPACE__.'\Bar'); - $pass = new AutowirePass(); - $pass->process($container); + (new ResolveClassPass())->process($container); + (new AutowirePass())->process($container); $this->assertCount(0, $container->getDefinition('bar')->getArguments()); } /** * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException - * @expectedExceptionMessage Cannot autowire service "a": argument $r of method Symfony\Component\DependencyInjection\Tests\Compiler\BadTypeHintedArgument::__construct() has type "Symfony\Component\DependencyInjection\Tests\Compiler\NotARealClass" but this class does not exist. + * @expectedExceptionMessage Cannot autowire service "a": argument "$r" of method "Symfony\Component\DependencyInjection\Tests\Compiler\BadTypeHintedArgument::__construct()" has type "Symfony\Component\DependencyInjection\Tests\Compiler\NotARealClass" but this class does not exist. */ public function testClassNotFoundThrowsException() { @@ -310,7 +318,7 @@ public function testClassNotFoundThrowsException() /** * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException - * @expectedExceptionMessage Cannot autowire service "a": argument $r of method Symfony\Component\DependencyInjection\Tests\Compiler\BadParentTypeHintedArgument::__construct() has type "Symfony\Component\DependencyInjection\Tests\Compiler\OptionalServiceClass" but this class does not exist. + * @expectedExceptionMessage Cannot autowire service "a": argument "$r" of method "Symfony\Component\DependencyInjection\Tests\Compiler\BadParentTypeHintedArgument::__construct()" has type "Symfony\Component\DependencyInjection\Tests\Compiler\OptionalServiceClass" but this class does not exist. */ public function testParentClassNotFoundThrowsException() { @@ -323,28 +331,29 @@ public function testParentClassNotFoundThrowsException() $pass->process($container); } + /** + * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException + * @expectedExceptionMessage Cannot autowire service "bar": argument "$foo" of method "Symfony\Component\DependencyInjection\Tests\Compiler\Bar::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\Foo" but this service is abstract. This type-hint could be aliased to the existing "foo" service. + */ public function testDontUseAbstractServices() { $container = new ContainerBuilder(); - $container->register('abstract_foo', __NAMESPACE__.'\Foo')->setAbstract(true); + $container->register(Foo::class)->setAbstract(true); $container->register('foo', __NAMESPACE__.'\Foo'); $container->register('bar', __NAMESPACE__.'\Bar')->setAutowired(true); - $pass = new AutowirePass(); - $pass->process($container); - - $arguments = $container->getDefinition('bar')->getArguments(); - $this->assertSame('foo', (string) $arguments[0]); + (new ResolveClassPass())->process($container); + (new AutowirePass())->process($container); } public function testSomeSpecificArgumentsAreSet() { $container = new ContainerBuilder(); - $container->register('foo', __NAMESPACE__.'\Foo'); - $container->register('a', __NAMESPACE__.'\A'); - $container->register('dunglas', __NAMESPACE__.'\Dunglas'); + $container->register('foo', Foo::class); + $container->register(A::class); + $container->register(Dunglas::class); $container->register('multiple', __NAMESPACE__.'\MultipleArguments') ->setAutowired(true) // set the 2nd (index 1) argument only: autowire the first and third @@ -353,15 +362,15 @@ public function testSomeSpecificArgumentsAreSet() 1 => new Reference('foo'), )); - $pass = new AutowirePass(); - $pass->process($container); + (new ResolveClassPass())->process($container); + (new AutowirePass())->process($container); $definition = $container->getDefinition('multiple'); $this->assertEquals( array( - new Reference('a'), + new Reference(A::class), new Reference('foo'), - new Reference('dunglas'), + new Reference(Dunglas::class), ), $definition->getArguments() ); @@ -369,34 +378,32 @@ public function testSomeSpecificArgumentsAreSet() /** * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException - * @expectedExceptionMessage Cannot autowire service "arg_no_type_hint": argument $foo of method Symfony\Component\DependencyInjection\Tests\Compiler\MultipleArguments::__construct() must have a type-hint or be given a value explicitly. + * @expectedExceptionMessage Cannot autowire service "arg_no_type_hint": argument "$foo" of method "Symfony\Component\DependencyInjection\Tests\Compiler\MultipleArguments::__construct()" must have a type-hint or be given a value explicitly. */ public function testScalarArgsCannotBeAutowired() { $container = new ContainerBuilder(); - $container->register('a', __NAMESPACE__.'\A'); - $container->register('dunglas', __NAMESPACE__.'\Dunglas'); + $container->register(A::class); + $container->register(Dunglas::class); $container->register('arg_no_type_hint', __NAMESPACE__.'\MultipleArguments') ->setAutowired(true); - $pass = new AutowirePass(); - $pass->process($container); - - $container->getDefinition('arg_no_type_hint'); + (new ResolveClassPass())->process($container); + (new AutowirePass())->process($container); } public function testOptionalScalarNotReallyOptionalUsesDefaultValue() { $container = new ContainerBuilder(); - $container->register('a', __NAMESPACE__.'\A'); - $container->register('lille', __NAMESPACE__.'\Lille'); + $container->register(A::class); + $container->register(Lille::class); $definition = $container->register('not_really_optional_scalar', __NAMESPACE__.'\MultipleArgumentsOptionalScalarNotReallyOptional') ->setAutowired(true); - $pass = new AutowirePass(); - $pass->process($container); + (new ResolveClassPass())->process($container); + (new AutowirePass())->process($container); $this->assertSame('default_val', $definition->getArgument(1)); } @@ -405,21 +412,21 @@ public function testOptionalScalarArgsDontMessUpOrder() { $container = new ContainerBuilder(); - $container->register('a', __NAMESPACE__.'\A'); - $container->register('lille', __NAMESPACE__.'\Lille'); + $container->register(A::class); + $container->register(Lille::class); $container->register('with_optional_scalar', __NAMESPACE__.'\MultipleArgumentsOptionalScalar') ->setAutowired(true); - $pass = new AutowirePass(); - $pass->process($container); + (new ResolveClassPass())->process($container); + (new AutowirePass())->process($container); $definition = $container->getDefinition('with_optional_scalar'); $this->assertEquals( array( - new Reference('a'), + new Reference(A::class), // use the default value 'default_val', - new Reference('lille'), + new Reference(Lille::class), ), $definition->getArguments() ); @@ -429,19 +436,19 @@ public function testOptionalScalarArgsNotPassedIfLast() { $container = new ContainerBuilder(); - $container->register('a', __NAMESPACE__.'\A'); - $container->register('lille', __NAMESPACE__.'\Lille'); + $container->register(A::class); + $container->register(Lille::class); $container->register('with_optional_scalar_last', __NAMESPACE__.'\MultipleArgumentsOptionalScalarLast') ->setAutowired(true); - $pass = new AutowirePass(); - $pass->process($container); + (new ResolveClassPass())->process($container); + (new AutowirePass())->process($container); $definition = $container->getDefinition('with_optional_scalar_last'); $this->assertEquals( array( - new Reference('a'), - new Reference('lille'), + new Reference(A::class), + new Reference(Lille::class), ), $definition->getArguments() ); @@ -450,10 +457,10 @@ public function testOptionalScalarArgsNotPassedIfLast() public function testSetterInjection() { $container = new ContainerBuilder(); - $container->register('app_foo', Foo::class); - $container->register('app_a', A::class); - $container->register('app_collision_a', CollisionA::class); - $container->register('app_collision_b', CollisionB::class); + $container->register(Foo::class); + $container->register(A::class); + $container->register(CollisionA::class); + $container->register(CollisionB::class); // manually configure *one* call, to override autowiring $container @@ -462,8 +469,8 @@ public function testSetterInjection() ->addMethodCall('setWithCallsConfigured', array('manual_arg1', 'manual_arg2')) ; - $pass = new AutowirePass(); - $pass->process($container); + (new ResolveClassPass())->process($container); + (new AutowirePass())->process($container); $methodCalls = $container->getDefinition('setter_injection')->getMethodCalls(); @@ -479,7 +486,7 @@ public function testSetterInjection() ); // test setFoo args $this->assertEquals( - array(new Reference('app_foo')), + array(new Reference(Foo::class)), $methodCalls[1][1] ); } @@ -487,10 +494,10 @@ public function testSetterInjection() public function testExplicitMethodInjection() { $container = new ContainerBuilder(); - $container->register('app_foo', Foo::class); - $container->register('app_a', A::class); - $container->register('app_collision_a', CollisionA::class); - $container->register('app_collision_b', CollisionB::class); + $container->register(Foo::class); + $container->register(A::class); + $container->register(CollisionA::class); + $container->register(CollisionB::class); $container ->register('setter_injection', SetterInjection::class) @@ -498,8 +505,8 @@ public function testExplicitMethodInjection() ->addMethodCall('notASetter', array()) ; - $pass = new AutowirePass(); - $pass->process($container); + (new ResolveClassPass())->process($container); + (new AutowirePass())->process($container); $methodCalls = $container->getDefinition('setter_injection')->getMethodCalls(); @@ -508,7 +515,7 @@ public function testExplicitMethodInjection() array_column($methodCalls, 0) ); $this->assertEquals( - array(new Reference('app_a')), + array(new Reference(A::class)), $methodCalls[0][1] ); } @@ -519,7 +526,6 @@ public function testTypedReference() $container ->register('bar', Bar::class) - ->setAutowired(true) ->setProperty('a', array(new TypedReference(A::class, A::class))) ; @@ -580,7 +586,7 @@ public function testIgnoreServiceWithClassNotExisting() /** * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException - * @expectedExceptionMessage Cannot autowire service "setter_injection_collision": multiple candidate services exist for interface "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface". This type-hint could be aliased to one of these existing services: "c1", "c2". + * @expectedExceptionMessage Cannot autowire service "setter_injection_collision": argument "$collision" of method "Symfony\Component\DependencyInjection\Tests\Compiler\SetterInjectionCollision::setMultipleInstancesForOneArg()" references interface "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" but no such service exists. This type-hint could be aliased to one of these existing services: "c1", "c2". */ public function testSetterInjectionCollisionThrowsException() { @@ -595,6 +601,10 @@ public function testSetterInjectionCollisionThrowsException() $pass->process($container); } + /** + * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException + * @expectedExceptionMessage Cannot autowire service "bar": argument "$foo" of method "Symfony\Component\DependencyInjection\Tests\Compiler\Bar::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\Foo" but no such service exists. This type-hint could be aliased to the existing "foo" service. + */ public function testProcessDoesNotTriggerDeprecations() { $container = new ContainerBuilder(); @@ -610,31 +620,31 @@ public function testEmptyStringIsKept() { $container = new ContainerBuilder(); - $container->register('a', __NAMESPACE__.'\A'); - $container->register('lille', __NAMESPACE__.'\Lille'); + $container->register(A::class); + $container->register(Lille::class); $container->register('foo', __NAMESPACE__.'\MultipleArgumentsOptionalScalar') ->setAutowired(true) ->setArguments(array('', '')); - $pass = new AutowirePass(); - $pass->process($container); + (new ResolveClassPass())->process($container); + (new AutowirePass())->process($container); - $this->assertEquals(array(new Reference('a'), '', new Reference('lille')), $container->getDefinition('foo')->getArguments()); + $this->assertEquals(array(new Reference(A::class), '', new Reference(Lille::class)), $container->getDefinition('foo')->getArguments()); } public function testWithFactory() { $container = new ContainerBuilder(); - $container->register('foo', Foo::class); + $container->register(Foo::class); $definition = $container->register('a', A::class) ->setFactory(array(A::class, 'create')) ->setAutowired(true); - $pass = new AutowirePass(); - $pass->process($container); + (new ResolveClassPass())->process($container); + (new AutowirePass())->process($container); - $this->assertEquals(array(new Reference('foo')), $definition->getArguments()); + $this->assertEquals(array(new Reference(Foo::class)), $definition->getArguments()); } /** @@ -656,8 +666,6 @@ public function testNotWireableCalls($method, $expectedMsg) $foo->addMethodCall($method, array()); } - $pass = new AutowirePass(); - if (method_exists($this, 'expectException')) { $this->expectException(RuntimeException::class); $this->expectExceptionMessage($expectedMsg); @@ -665,68 +673,21 @@ public function testNotWireableCalls($method, $expectedMsg) $this->setExpectedException(RuntimeException::class, $expectedMsg); } - $pass->process($container); + (new ResolveClassPass())->process($container); + (new AutowirePass())->process($container); } public function provideNotWireableCalls() { return array( - array('setNotAutowireable', 'Cannot autowire service "foo": argument $n of method Symfony\Component\DependencyInjection\Tests\Compiler\NotWireable::setNotAutowireable() has type "Symfony\Component\DependencyInjection\Tests\Compiler\NotARealClass" but this class does not exist.'), + array('setNotAutowireable', 'Cannot autowire service "foo": argument "$n" of method "Symfony\Component\DependencyInjection\Tests\Compiler\NotWireable::setNotAutowireable()" has type "Symfony\Component\DependencyInjection\Tests\Compiler\NotARealClass" but this class does not exist.'), array(null, 'Cannot autowire service "foo": method "Symfony\Component\DependencyInjection\Tests\Compiler\NotWireable::setProtectedMethod()" must be public.'), ); } /** * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException - * @expectedExceptionMessage Cannot autowire service "j": multiple candidate services exist for class "Symfony\Component\DependencyInjection\Tests\Compiler\I". This type-hint could be aliased to one of these existing services: "f", "i"; or be updated to "Symfony\Component\DependencyInjection\Tests\Compiler\IInterface". - */ - public function testAlternatives() - { - $container = new ContainerBuilder(); - - $container->setAlias(IInterface::class, 'i'); - $container->register('f', F::class); - $container->register('i', I::class); - $container->register('j', J::class) - ->setAutowired(true); - - $pass = new AutowirePass(); - $pass->process($container); - } - - public function testById() - { - $container = new ContainerBuilder(); - - $container->register(A::class, A::class); - $container->register(DInterface::class, F::class); - $container->register('d', D::class) - ->setAutowired(Definition::AUTOWIRE_BY_ID); - - $pass = new AutowirePass(); - $pass->process($container); - - $this->assertSame(array('service_container', A::class, DInterface::class, 'd'), array_keys($container->getDefinitions())); - $this->assertEquals(array(new Reference(A::class), new Reference(DInterface::class)), $container->getDefinition('d')->getArguments()); - } - - public function testByIdDoesNotAutoregister() - { - $container = new ContainerBuilder(); - - $container->register('f', F::class); - $container->register('e', E::class) - ->setAutowired(Definition::AUTOWIRE_BY_ID); - - $pass = new AutowirePass(); - $pass->process($container); - - $this->assertSame(array('service_container', 'f', 'e'), array_keys($container->getDefinitions())); - } - - /** - * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException - * @expectedExceptionMessage Cannot autowire service "j": argument $i of method Symfony\Component\DependencyInjection\Tests\Compiler\J::__construct() references class "Symfony\Component\DependencyInjection\Tests\Compiler\I" but no such service exists. This type-hint could be aliased to the existing "i" service; or be updated to "Symfony\Component\DependencyInjection\Tests\Compiler\IInterface". + * @expectedExceptionMessage Cannot autowire service "j": argument "$i" of method "Symfony\Component\DependencyInjection\Tests\Compiler\J::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\I" but no such service exists. This type-hint could be aliased to the existing "i" service; or be updated to "Symfony\Component\DependencyInjection\Tests\Compiler\IInterface". */ public function testByIdAlternative() { @@ -735,7 +696,7 @@ public function testByIdAlternative() $container->setAlias(IInterface::class, 'i'); $container->register('i', I::class); $container->register('j', J::class) - ->setAutowired(Definition::AUTOWIRE_BY_ID); + ->setAutowired(true); $pass = new AutowirePass(); $pass->process($container); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/RegisterServiceSubscribersPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/RegisterServiceSubscribersPassTest.php index 2d6b79772d4f1..75c10bbdc7885 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/RegisterServiceSubscribersPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/RegisterServiceSubscribersPassTest.php @@ -71,7 +71,6 @@ public function testNoAttributes() $foo = $container->getDefinition('foo'); $locator = $container->getDefinition((string) $foo->getArgument(0)); - $this->assertFalse($locator->isAutowired()); $this->assertFalse($locator->isPublic()); $this->assertSame(ServiceLocator::class, $locator->getClass()); @@ -102,7 +101,6 @@ public function testWithAttributes() $foo = $container->getDefinition('foo'); $locator = $container->getDefinition((string) $foo->getArgument(0)); - $this->assertTrue($locator->isAutowired()); $this->assertFalse($locator->isPublic()); $this->assertSame(ServiceLocator::class, $locator->getClass()); diff --git a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php index ed830321932de..5580d3c3a4f1a 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php @@ -967,13 +967,13 @@ public function testAutowiring() { $container = new ContainerBuilder(); - $container->register('a', __NAMESPACE__.'\A'); + $container->register(A::class); $bDefinition = $container->register('b', __NAMESPACE__.'\B'); $bDefinition->setAutowired(true); $container->compile(); - $this->assertEquals('a', (string) $container->getDefinition('b')->getArgument(0)); + $this->assertEquals(A::class, (string) $container->getDefinition('b')->getArgument(0)); } public function testClosureProxy() diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services24.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services24.php index 8deafa468c0d3..be8cb0678c19a 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services24.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services24.php @@ -70,7 +70,7 @@ public function isFrozen() * This service is shared. * This method always returns the same instance of the service. * - * This service is autowired by types. + * This service is autowired. * * @return \Foo A Foo instance */ diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_subscriber.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_subscriber.php index a29792c3e4d42..018934cd3d96c 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_subscriber.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_subscriber.php @@ -91,7 +91,7 @@ protected function getTestServiceSubscriberService() * This service is shared. * This method always returns the same instance of the service. * - * This service is autowired by types. + * This service is autowired. * * @return \TestServiceSubscriber A TestServiceSubscriber instance */ @@ -118,7 +118,7 @@ protected function getFooServiceService() * If you want to be able to request this service from the container directly, * make it public, otherwise you might end up with broken code. * - * This service is autowired by types. + * This service is autowired. * * @return \stdClass A stdClass instance */ diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services24.xml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services24.xml index c0815cd51229d..c4e32cb634e0c 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services24.xml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services24.xml @@ -2,7 +2,7 @@ - + diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services24.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services24.yml index 977e30ffcca23..afed157017f4d 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services24.yml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services24.yml @@ -5,7 +5,7 @@ services: synthetic: true foo: class: Foo - autowire: by_type + autowire: true Psr\Container\ContainerInterface: alias: service_container public: false diff --git a/src/Symfony/Component/HttpKernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php b/src/Symfony/Component/HttpKernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php index 24f64a6d31e29..ee1202b20a191 100644 --- a/src/Symfony/Component/HttpKernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php +++ b/src/Symfony/Component/HttpKernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php @@ -52,7 +52,6 @@ public function process(ContainerBuilder $container) continue; } $class = $def->getClass(); - $autowired = $def->getAutowired(); // resolve service class, taking parent definitions into account while (!$class && $def instanceof ChildDefinition) { @@ -129,7 +128,7 @@ public function process(ContainerBuilder $container) } // register the maps as a per-method service-locators if ($args) { - $controllers[$id.':'.$r->name] = ServiceLocatorTagPass::register($container, $args, $autowired); + $controllers[$id.':'.$r->name] = ServiceLocatorTagPass::register($container, $args); } } } diff --git a/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/FragmentRendererPassTest.php b/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/FragmentRendererPassTest.php index 820ae81dfcde1..d28c6eca57d92 100644 --- a/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/FragmentRendererPassTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/FragmentRendererPassTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\HttpKernel\Tests\DependencyInjection; use PHPUnit\Framework\TestCase; +use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\DependencyInjection\FragmentRendererPass; @@ -58,11 +59,7 @@ public function testValidContentRenderer() 'my_content_renderer' => array(array('alias' => 'foo')), ); - $renderer = $this->getMockBuilder('Symfony\Component\DependencyInjection\Definition')->getMock(); - $renderer - ->expects($this->once()) - ->method('replaceArgument') - ->with(0, $this->equalTo(new Reference('service_locator.5ae0a401097c64ca63ed976c71bc9642'))); + $renderer = new Definition('', array(null)); $definition = $this->getMockBuilder('Symfony\Component\DependencyInjection\Definition')->getMock(); $definition->expects($this->atLeastOnce()) @@ -90,6 +87,8 @@ public function testValidContentRenderer() $pass = new FragmentRendererPass(); $pass->process($builder); + + $this->assertInstanceOf(Reference::class, $renderer->getArgument(0)); } } diff --git a/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RegisterControllerArgumentLocatorsPassTest.php b/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RegisterControllerArgumentLocatorsPassTest.php index 86d1532b491fa..b03f34d972f10 100644 --- a/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RegisterControllerArgumentLocatorsPassTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RegisterControllerArgumentLocatorsPassTest.php @@ -15,7 +15,6 @@ use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerInterface; -use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\ServiceLocator; use Symfony\Component\DependencyInjection\TypedReference; use Symfony\Component\HttpKernel\DependencyInjection\RegisterControllerArgumentLocatorsPass; @@ -130,7 +129,6 @@ public function testAllActions() $resolver = $container->register('argument_resolver.service')->addArgument(array()); $container->register('foo', RegisterTestController::class) - ->setAutowired(true) ->addTag('controller.service_arguments') ; @@ -139,13 +137,13 @@ public function testAllActions() $locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0); - $this->assertEquals(array('foo:fooAction' => new ServiceClosureArgument(new Reference('service_locator.d964744f7278cba85dee823607f8c07f'))), $locator); + $this->assertEquals(array('foo:fooAction'), array_keys($locator)); + $this->assertInstanceof(ServiceClosureArgument::class, $locator['foo:fooAction']); $locator = $container->getDefinition((string) $locator['foo:fooAction']->getValues()[0]); $this->assertSame(ServiceLocator::class, $locator->getClass()); $this->assertFalse($locator->isPublic()); - $this->assertTrue($locator->isAutowired()); $expected = array('bar' => new ServiceClosureArgument(new TypedReference('stdClass', 'stdClass', ContainerInterface::IGNORE_ON_INVALID_REFERENCE, false))); $this->assertEquals($expected, $locator->getArgument(0)); @@ -166,7 +164,6 @@ public function testExplicitArgument() $locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0); $locator = $container->getDefinition((string) $locator['foo:fooAction']->getValues()[0]); - $this->assertFalse($locator->isAutowired()); $expected = array('bar' => new ServiceClosureArgument(new TypedReference('bar', 'stdClass', ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, false))); $this->assertEquals($expected, $locator->getArgument(0)); diff --git a/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RemoveEmptyControllerArgumentLocatorsPassTest.php b/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RemoveEmptyControllerArgumentLocatorsPassTest.php index f633fc33454f7..786c6f7ed8348 100644 --- a/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RemoveEmptyControllerArgumentLocatorsPassTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RemoveEmptyControllerArgumentLocatorsPassTest.php @@ -12,7 +12,6 @@ namespace Symfony\Component\HttpKernel\Tests\DependencyInjection; use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; use Symfony\Component\DependencyInjection\Compiler\ResolveInvalidReferencesPass; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; @@ -74,10 +73,10 @@ public function testSameIdClass() (new RemoveEmptyControllerArgumentLocatorsPass())->process($container); $expected = array( - RegisterTestController::class.':fooAction' => new ServiceClosureArgument(new Reference('service_locator.37b6201ea2e9e6ade00ab09ae7a6ceb3')), - RegisterTestController::class.'::fooAction' => new ServiceClosureArgument(new Reference('service_locator.37b6201ea2e9e6ade00ab09ae7a6ceb3')), + RegisterTestController::class.':fooAction', + RegisterTestController::class.'::fooAction', ); - $this->assertEquals($expected, $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0)); + $this->assertEquals($expected, array_keys($container->getDefinition((string) $resolver->getArgument(0))->getArgument(0))); } }