[BC BREAK][DI] Always autowire "by id" instead of using reflection against all existing services

This commit is contained in:
Nicolas Grekas 2017-04-04 19:35:51 +02:00
parent 12bb392a39
commit cc5e582dcf
29 changed files with 218 additions and 351 deletions

View File

@ -80,6 +80,8 @@ Debug
DependencyInjection 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] `_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. * [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.

View File

@ -73,6 +73,8 @@ Debug
DependencyInjection 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. * `_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. * 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.

View File

@ -221,7 +221,7 @@ class JsonDescriptor extends Descriptor
'lazy' => $definition->isLazy(), 'lazy' => $definition->isLazy(),
'shared' => $definition->isShared(), 'shared' => $definition->isShared(),
'abstract' => $definition->isAbstract(), '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) { foreach ($definition->getAutowiringTypes(false) as $autowiringType) {

View File

@ -182,7 +182,7 @@ class MarkdownDescriptor extends Descriptor
."\n".'- Lazy: '.($definition->isLazy() ? 'yes' : 'no') ."\n".'- Lazy: '.($definition->isLazy() ? 'yes' : 'no')
."\n".'- Shared: '.($definition->isShared() ? 'yes' : 'no') ."\n".'- Shared: '.($definition->isShared() ? 'yes' : 'no')
."\n".'- Abstract: '.($definition->isAbstract() ? '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) { foreach ($definition->getAutowiringTypes(false) as $autowiringType) {

View File

@ -295,7 +295,7 @@ class TextDescriptor extends Descriptor
$tableRows[] = array('Lazy', $definition->isLazy() ? 'yes' : 'no'); $tableRows[] = array('Lazy', $definition->isLazy() ? 'yes' : 'no');
$tableRows[] = array('Shared', $definition->isShared() ? 'yes' : 'no'); $tableRows[] = array('Shared', $definition->isShared() ? 'yes' : 'no');
$tableRows[] = array('Abstract', $definition->isAbstract() ? '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)) { if ($autowiringTypes = $definition->getAutowiringTypes(false)) {
$tableRows[] = array('Autowiring Types', implode(', ', $autowiringTypes)); $tableRows[] = array('Autowiring Types', implode(', ', $autowiringTypes));

View File

@ -371,7 +371,7 @@ class XmlDescriptor extends Descriptor
$serviceXML->setAttribute('lazy', $definition->isLazy() ? 'true' : 'false'); $serviceXML->setAttribute('lazy', $definition->isLazy() ? 'true' : 'false');
$serviceXML->setAttribute('shared', $definition->isShared() ? 'true' : 'false'); $serviceXML->setAttribute('shared', $definition->isShared() ? 'true' : 'false');
$serviceXML->setAttribute('abstract', $definition->isAbstract() ? '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()); $serviceXML->setAttribute('file', $definition->getFile());
$calls = $definition->getMethodCalls(); $calls = $definition->getMethodCalls();

View File

@ -4,6 +4,8 @@ CHANGELOG
3.3.0 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 "ServiceSubscriberInterface" - to allow for per-class explicit service-locator definitions
* added "container.service_locator" tag for defining service-locator services * added "container.service_locator" tag for defining service-locator services
* added anonymous services support in YAML configuration files using the `!service` tag. * added anonymous services support in YAML configuration files using the `!service` tag.

View File

@ -31,7 +31,6 @@ class AutowirePass extends AbstractRecursivePass
private $types; private $types;
private $ambiguousServiceTypes = array(); private $ambiguousServiceTypes = array();
private $autowired = array(); private $autowired = array();
private $currentDefinition;
/** /**
* {@inheritdoc} * {@inheritdoc}
@ -77,7 +76,7 @@ class AutowirePass extends AbstractRecursivePass
*/ */
protected function processValue($value, $isRoot = false) 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())) { if ($ref = $this->getAutowiredReference($value->getType(), $value->canBeAutoregistered())) {
$value = new TypedReference((string) $ref, $value->getType(), $value->getInvalidBehavior(), $value->canBeAutoregistered()); $value = new TypedReference((string) $ref, $value->getType(), $value->getInvalidBehavior(), $value->canBeAutoregistered());
} else { } else {
@ -87,45 +86,37 @@ class AutowirePass extends AbstractRecursivePass
if (!$value instanceof Definition) { if (!$value instanceof Definition) {
return parent::processValue($value, $isRoot); return parent::processValue($value, $isRoot);
} }
if (!$value->isAutowired() || $value->isAbstract() || !$value->getClass()) {
$parentDefinition = $this->currentDefinition; return parent::processValue($value, $isRoot);
$this->currentDefinition = $value; }
if (!$reflectionClass = $this->container->getReflectionClass($value->getClass())) {
try { $this->container->log($this, sprintf('Skipping service "%s": Class or interface "%s" does not exist.', $this->currentId, $value->getClass()));
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();
if ($constructor = $this->getConstructor($value, false)) {
array_unshift($methodCalls, array($constructor, $value->getArguments()));
}
$methodCalls = $this->autowireCalls($reflectionClass, $methodCalls, $autowiredMethods);
if ($constructor) {
list(, $arguments) = array_shift($methodCalls);
if ($arguments !== $value->getArguments()) {
$value->setArguments($arguments);
}
}
if ($methodCalls !== $value->getMethodCalls()) {
$value->setMethodCalls($methodCalls);
}
return parent::processValue($value, $isRoot); return parent::processValue($value, $isRoot);
} finally {
$this->currentDefinition = $parentDefinition;
} }
$autowiredMethods = $this->getMethodsToAutowire($reflectionClass);
$methodCalls = $value->getMethodCalls();
if ($constructor = $this->getConstructor($value, false)) {
array_unshift($methodCalls, array($constructor, $value->getArguments()));
}
$methodCalls = $this->autowireCalls($reflectionClass, $methodCalls, $autowiredMethods);
if ($constructor) {
list(, $arguments) = array_shift($methodCalls);
if ($arguments !== $value->getArguments()) {
$value->setArguments($arguments);
}
}
if ($methodCalls !== $value->getMethodCalls()) {
$value->setMethodCalls($methodCalls);
}
return parent::processValue($value, $isRoot);
} }
/** /**
@ -186,7 +177,7 @@ class AutowirePass extends AbstractRecursivePass
$reflectionMethod = $autowiredMethods[$lcMethod]; $reflectionMethod = $autowiredMethods[$lcMethod];
unset($autowiredMethods[$lcMethod]); unset($autowiredMethods[$lcMethod]);
} else { } else {
$reflectionMethod = $this->getReflectionMethod($this->currentDefinition, $method); $reflectionMethod = $this->getReflectionMethod(new Definition($reflectionClass->name), $method);
} }
$arguments = $this->autowireMethod($reflectionMethod, $arguments); $arguments = $this->autowireMethod($reflectionMethod, $arguments);
@ -242,7 +233,7 @@ class AutowirePass extends AbstractRecursivePass
// no default value? Then fail // no default value? Then fail
if (!$parameter->isDefaultValueAvailable()) { 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 // specifically pass the default value
@ -251,8 +242,8 @@ class AutowirePass extends AbstractRecursivePass
continue; continue;
} }
if (!$value = $this->getAutowiredReference($type)) { 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)); $failureMessage = $this->createTypeNotFoundMessage($type, sprintf('argument "$%s" of method "%s()"', $parameter->name, $class !== $this->currentId ? $class.'::'.$method : $method));
if ($parameter->isDefaultValueAvailable()) { if ($parameter->isDefaultValueAvailable()) {
$value = $parameter->getDefaultValue(); $value = $parameter->getDefaultValue();
@ -286,19 +277,13 @@ class AutowirePass extends AbstractRecursivePass
/** /**
* @return Reference|null A reference to the service matching the given type, if any * @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()) { if ($this->container->has($type) && !$this->container->findDefinition($type)->isAbstract()) {
return new Reference($type); return new Reference($type);
} }
if (Definition::AUTOWIRE_BY_ID === $this->currentDefinition->getAutowired()) {
return;
}
if (isset($this->autowired[$type])) { if (isset($this->autowired[$type])) {
return $this->autowired[$type] ? new Reference($this->autowired[$type]) : null; return $this->autowired[$type] ? new Reference($this->autowired[$type]) : null;
} }
@ -307,19 +292,11 @@ class AutowirePass extends AbstractRecursivePass
$this->populateAvailableTypes(); $this->populateAvailableTypes();
} }
if (isset($this->types[$type])) { if (isset($this->definedTypes[$type])) {
$this->container->log($this, sprintf('Service "%s" matches type "%s" and has been autowired into service "%s".', $this->types[$type], $type, $this->currentId));
return new Reference($this->types[$type]); return new Reference($this->types[$type]);
} }
if (isset($this->ambiguousServiceTypes[$type])) { if ($autoRegister && !isset($this->types[$type]) && !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) {
return $this->createAutowiredDefinition($type); return $this->createAutowiredDefinition($type);
} }
} }
@ -355,22 +332,8 @@ class AutowirePass extends AbstractRecursivePass
unset($this->ambiguousServiceTypes[$type]); unset($this->ambiguousServiceTypes[$type]);
} }
if ($deprecated = $definition->isDeprecated()) { if ($definition->isDeprecated() || !$reflectionClass = $this->container->getReflectionClass($definition->getClass(), true)) {
$prevErrorHandler = set_error_handler(function ($level, $message, $file, $line) use (&$prevErrorHandler) { return;
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();
}
} }
foreach ($reflectionClass->getInterfaces() as $reflectionInterface) { foreach ($reflectionClass->getInterfaces() as $reflectionInterface) {
@ -429,10 +392,9 @@ class AutowirePass extends AbstractRecursivePass
return; return;
} }
$currentDefinition = $this->currentDefinition;
$currentId = $this->currentId; $currentId = $this->currentId;
$this->currentId = $this->autowired[$type] = $argumentId = sprintf('autowired.%s', $type); $this->currentId = $this->autowired[$type] = $argumentId = sprintf('autowired.%s', $type);
$this->currentDefinition = $argumentDefinition = new Definition($type); $argumentDefinition = new Definition($type);
$argumentDefinition->setPublic(false); $argumentDefinition->setPublic(false);
$argumentDefinition->setAutowired(true); $argumentDefinition->setAutowired(true);
@ -446,7 +408,6 @@ class AutowirePass extends AbstractRecursivePass
return; return;
} finally { } finally {
$this->currentId = $currentId; $this->currentId = $currentId;
$this->currentDefinition = $currentDefinition;
} }
$this->container->log($this, sprintf('Type "%s" has been auto-registered for service "%s".', $type, $this->currentId)); $this->container->log($this, sprintf('Type "%s" has been auto-registered for service "%s".', $type, $this->currentId));
@ -456,20 +417,14 @@ class AutowirePass extends AbstractRecursivePass
private function createTypeNotFoundMessage($type, $label) private function createTypeNotFoundMessage($type, $label)
{ {
$autowireById = Definition::AUTOWIRE_BY_ID === $this->currentDefinition->getAutowired(); if (!$r = $this->container->getReflectionClass($type, true)) {
if (!$classOrInterface = class_exists($type, $autowireById) ? 'class' : (interface_exists($type, false) ? 'interface' : null)) { $message = sprintf('has type "%s" but this class does not exist.', $type);
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));
} else { } 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) private function createTypeAlternatives($type)

View File

@ -38,9 +38,11 @@ class RegisterServiceSubscribersPass extends AbstractRecursivePass
} }
$serviceMap = array(); $serviceMap = array();
$autowire = $value->isAutowired();
foreach ($value->getTag('container.service_subscriber') as $attributes) { foreach ($value->getTag('container.service_subscriber') as $attributes) {
if (!$attributes) { if (!$attributes) {
$autowire = true;
continue; continue;
} }
ksort($attributes); ksort($attributes);
@ -82,6 +84,9 @@ class RegisterServiceSubscribersPass extends AbstractRecursivePass
$key = $type; $key = $type;
} }
if (!isset($serviceMap[$key])) { 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); $serviceMap[$key] = new Reference($type);
} }
@ -95,7 +100,7 @@ class RegisterServiceSubscribersPass extends AbstractRecursivePass
} }
$serviceLocator = $this->serviceLocator; $serviceLocator = $this->serviceLocator;
$this->serviceLocator = (string) ServiceLocatorTagPass::register($this->container, $subscriberMap, $value->getAutowired()); $this->serviceLocator = (string) ServiceLocatorTagPass::register($this->container, $subscriberMap);
try { try {
return parent::processValue($value); return parent::processValue($value);

View File

@ -100,7 +100,7 @@ class ResolveDefinitionTemplatesPass extends AbstractRecursivePass
$def->setFile($parentDef->getFile()); $def->setFile($parentDef->getFile());
$def->setPublic($parentDef->isPublic()); $def->setPublic($parentDef->isPublic());
$def->setLazy($parentDef->isLazy()); $def->setLazy($parentDef->isLazy());
$def->setAutowired($parentDef->getAutowired()); $def->setAutowired($parentDef->isAutowired());
self::mergeDefinition($def, $definition); self::mergeDefinition($def, $definition);
@ -146,7 +146,7 @@ class ResolveDefinitionTemplatesPass extends AbstractRecursivePass
$def->setDeprecated($definition->isDeprecated(), $definition->getDeprecationMessage('%service_id%')); $def->setDeprecated($definition->isDeprecated(), $definition->getDeprecationMessage('%service_id%'));
} }
if (isset($changes['autowired'])) { if (isset($changes['autowired'])) {
$def->setAutowired($definition->getAutowired()); $def->setAutowired($definition->isAutowired());
} }
if (isset($changes['decorated_service'])) { if (isset($changes['decorated_service'])) {
$decoratedService = $definition->getDecoratedService(); $decoratedService = $definition->getDecoratedService();

View File

@ -75,11 +75,10 @@ final class ServiceLocatorTagPass extends AbstractRecursivePass
/** /**
* @param ContainerBuilder $container * @param ContainerBuilder $container
* @param Reference[] $refMap * @param Reference[] $refMap
* @param int|bool $autowired
* *
* @return Reference * @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) { foreach ($refMap as $id => $ref) {
$refMap[$id] = new ServiceClosureArgument($ref); $refMap[$id] = new ServiceClosureArgument($ref);
@ -89,7 +88,6 @@ final class ServiceLocatorTagPass extends AbstractRecursivePass
$locator = (new Definition(ServiceLocator::class)) $locator = (new Definition(ServiceLocator::class))
->addArgument($refMap) ->addArgument($refMap)
->setPublic(false) ->setPublic(false)
->setAutowired($autowired)
->addTag('container.service_locator'); ->addTag('container.service_locator');
if (!$container->has($id = 'service_locator.'.md5(serialize($locator)))) { if (!$container->has($id = 'service_locator.'.md5(serialize($locator)))) {

View File

@ -21,9 +21,6 @@ use Symfony\Component\DependencyInjection\Exception\OutOfBoundsException;
*/ */
class Definition class Definition
{ {
const AUTOWIRE_BY_TYPE = 1;
const AUTOWIRE_BY_ID = 2;
private $class; private $class;
private $file; private $file;
private $factory; private $factory;
@ -40,7 +37,7 @@ class Definition
private $abstract = false; private $abstract = false;
private $lazy = false; private $lazy = false;
private $decoratedService; private $decoratedService;
private $autowired = 0; private $autowired = false;
private $autowiringTypes = array(); private $autowiringTypes = array();
protected $arguments; protected $arguments;
@ -699,16 +696,6 @@ class Definition
* @return bool * @return bool
*/ */
public function isAutowired() public function isAutowired()
{
return (bool) $this->autowired;
}
/**
* Gets the autowiring mode.
*
* @return int
*/
public function getAutowired()
{ {
return $this->autowired; return $this->autowired;
} }
@ -716,18 +703,13 @@ class Definition
/** /**
* Sets autowired. * Sets autowired.
* *
* @param bool|int $autowired * @param bool $autowired
* *
* @return $this * @return $this
*/ */
public function setAutowired($autowired) public function setAutowired($autowired)
{ {
$autowired = (int) $autowired; $this->autowired = (bool) $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;
return $this; return $this;
} }

View File

@ -646,11 +646,10 @@ EOF;
} }
if ($definition->isAutowired()) { if ($definition->isAutowired()) {
$autowired = Definition::AUTOWIRE_BY_TYPE === $definition->getAutowired() ? 'types' : 'ids';
$doc .= <<<EOF $doc .= <<<EOF
* *
* This service is autowired by {$autowired}. * This service is autowired.
EOF; EOF;
} }

View File

@ -195,7 +195,7 @@ class XmlDumper extends Dumper
} }
if ($definition->isAutowired()) { if ($definition->isAutowired()) {
$service->setAttribute('autowire', Definition::AUTOWIRE_BY_TYPE === $definition->getAutowired() ? 'by-type' : 'by-id'); $service->setAttribute('autowire', 'true');
} }
foreach ($definition->getAutowiringTypes(false) as $autowiringTypeValue) { foreach ($definition->getAutowiringTypes(false) as $autowiringTypeValue) {

View File

@ -106,7 +106,7 @@ class YamlDumper extends Dumper
} }
if ($definition->isAutowired()) { if ($definition->isAutowired()) {
$code .= sprintf(" autowire: %s\n", Definition::AUTOWIRE_BY_TYPE === $definition->getAutowired() ? 'by_type' : 'by_id'); $code .= " autowire: true\n";
} }
$autowiringTypesCode = ''; $autowiringTypesCode = '';

View File

@ -172,7 +172,7 @@ class XmlFileLoader extends FileLoader
} }
} }
if ($defaultsNode->hasAttribute('autowire')) { if ($defaultsNode->hasAttribute('autowire')) {
$defaults['autowire'] = $this->getAutowired($defaultsNode->getAttribute('autowire'), $file); $defaults['autowire'] = XmlUtils::phpize($defaultsNode->getAttribute('autowire'));
} }
if ($defaultsNode->hasAttribute('public')) { if ($defaultsNode->hasAttribute('public')) {
$defaults['public'] = XmlUtils::phpize($defaultsNode->getAttribute('public')); $defaults['public'] = XmlUtils::phpize($defaultsNode->getAttribute('public'));
@ -238,7 +238,7 @@ class XmlFileLoader extends FileLoader
} }
if ($value = $service->getAttribute('autowire')) { if ($value = $service->getAttribute('autowire')) {
$definition->setAutowired($this->getAutowired($value, $file)); $definition->setAutowired(XmlUtils::phpize($value));
} elseif (isset($defaults['autowire'])) { } elseif (isset($defaults['autowire'])) {
$definition->setAutowired($defaults['autowire']); $definition->setAutowired($defaults['autowire']);
} }
@ -656,23 +656,6 @@ EOF
} }
} }
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. * Converts a \DomElement object to a PHP array.
* *

View File

@ -486,14 +486,6 @@ class YamlFileLoader extends FileLoader
$autowire = isset($service['autowire']) ? $service['autowire'] : (isset($defaults['autowire']) ? $defaults['autowire'] : null); $autowire = isset($service['autowire']) ? $service['autowire'] : (isset($defaults['autowire']) ? $defaults['autowire'] : null);
if (null !== $autowire) { 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); $definition->setAutowired($autowire);
} }

View File

@ -102,7 +102,7 @@
<xsd:element name="tag" type="tag" minOccurs="0" maxOccurs="unbounded" /> <xsd:element name="tag" type="tag" minOccurs="0" maxOccurs="unbounded" />
</xsd:choice> </xsd:choice>
<xsd:attribute name="public" type="boolean" /> <xsd:attribute name="public" type="boolean" />
<xsd:attribute name="autowire" type="autowire" /> <xsd:attribute name="autowire" type="boolean" />
<xsd:attribute name="inherit-tags" type="boolean" /> <xsd:attribute name="inherit-tags" type="boolean" />
</xsd:complexType> </xsd:complexType>
@ -130,7 +130,7 @@
<xsd:attribute name="decorates" type="xsd:string" /> <xsd:attribute name="decorates" type="xsd:string" />
<xsd:attribute name="decoration-inner-name" type="xsd:string" /> <xsd:attribute name="decoration-inner-name" type="xsd:string" />
<xsd:attribute name="decoration-priority" type="xsd:integer" /> <xsd:attribute name="decoration-priority" type="xsd:integer" />
<xsd:attribute name="autowire" type="autowire" /> <xsd:attribute name="autowire" type="boolean" />
<xsd:attribute name="inherit-tags" type="boolean" /> <xsd:attribute name="inherit-tags" type="boolean" />
</xsd:complexType> </xsd:complexType>
@ -149,7 +149,7 @@
<xsd:attribute name="public" type="boolean" /> <xsd:attribute name="public" type="boolean" />
<xsd:attribute name="lazy" type="boolean" /> <xsd:attribute name="lazy" type="boolean" />
<xsd:attribute name="abstract" type="boolean" /> <xsd:attribute name="abstract" type="boolean" />
<xsd:attribute name="autowire" type="autowire" /> <xsd:attribute name="autowire" type="boolean" />
</xsd:complexType> </xsd:complexType>
<xsd:complexType name="prototype"> <xsd:complexType name="prototype">
@ -169,7 +169,7 @@
<xsd:attribute name="lazy" type="boolean" /> <xsd:attribute name="lazy" type="boolean" />
<xsd:attribute name="abstract" type="boolean" /> <xsd:attribute name="abstract" type="boolean" />
<xsd:attribute name="parent" type="xsd:string" /> <xsd:attribute name="parent" type="xsd:string" />
<xsd:attribute name="autowire" type="autowire" /> <xsd:attribute name="autowire" type="boolean" />
<xsd:attribute name="inherit-tags" type="boolean" /> <xsd:attribute name="inherit-tags" type="boolean" />
</xsd:complexType> </xsd:complexType>
@ -263,10 +263,4 @@
<xsd:pattern value="(%.+%|true|false)" /> <xsd:pattern value="(%.+%|true|false)" />
</xsd:restriction> </xsd:restriction>
</xsd:simpleType> </xsd:simpleType>
<xsd:simpleType name="autowire">
<xsd:restriction base="xsd:string">
<xsd:pattern value="(true|false|by-type|by-id)" />
</xsd:restriction>
</xsd:simpleType>
</xsd:schema> </xsd:schema>

View File

@ -13,8 +13,8 @@ namespace Symfony\Component\DependencyInjection\Tests\Compiler;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\Compiler\AutowirePass; use Symfony\Component\DependencyInjection\Compiler\AutowirePass;
use Symfony\Component\DependencyInjection\Compiler\ResolveClassPass;
use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Exception\RuntimeException; use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Tests\Fixtures\includes\FooVariadic; use Symfony\Component\DependencyInjection\Tests\Fixtures\includes\FooVariadic;
@ -29,15 +29,15 @@ class AutowirePassTest extends TestCase
{ {
$container = new ContainerBuilder(); $container = new ContainerBuilder();
$container->register('foo', __NAMESPACE__.'\Foo'); $container->register(Foo::class);
$barDefinition = $container->register('bar', __NAMESPACE__.'\Bar'); $barDefinition = $container->register('bar', __NAMESPACE__.'\Bar');
$barDefinition->setAutowired(true); $barDefinition->setAutowired(true);
$pass = new AutowirePass(); (new ResolveClassPass())->process($container);
$pass->process($container); (new AutowirePass())->process($container);
$this->assertCount(1, $container->getDefinition('bar')->getArguments()); $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 @@ class AutowirePassTest extends TestCase
public function testProcessVariadic() public function testProcessVariadic()
{ {
$container = new ContainerBuilder(); $container = new ContainerBuilder();
$container->register('foo', Foo::class); $container->register(Foo::class);
$definition = $container->register('fooVariadic', FooVariadic::class); $definition = $container->register('fooVariadic', FooVariadic::class);
$definition->setAutowired(true); $definition->setAutowired(true);
$pass = new AutowirePass(); (new ResolveClassPass())->process($container);
$pass->process($container); (new AutowirePass())->process($container);
$this->assertCount(1, $container->getDefinition('fooVariadic')->getArguments()); $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() public function testProcessAutowireParent()
{ {
$container = new ContainerBuilder(); $container = new ContainerBuilder();
$container->register('b', __NAMESPACE__.'\B'); $container->register(B::class);
$cDefinition = $container->register('c', __NAMESPACE__.'\C'); $cDefinition = $container->register('c', __NAMESPACE__.'\C');
$cDefinition->setAutowired(true); $cDefinition->setAutowired(true);
$pass = new AutowirePass(); (new ResolveClassPass())->process($container);
$pass->process($container); (new AutowirePass())->process($container);
$this->assertCount(1, $container->getDefinition('c')->getArguments()); $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() public function testProcessAutowireInterface()
{ {
$container = new ContainerBuilder(); $container = new ContainerBuilder();
$container->register('f', __NAMESPACE__.'\F'); $container->register(F::class);
$gDefinition = $container->register('g', __NAMESPACE__.'\G'); $gDefinition = $container->register('g', __NAMESPACE__.'\G');
$gDefinition->setAutowired(true); $gDefinition->setAutowired(true);
$pass = new AutowirePass(); (new ResolveClassPass())->process($container);
$pass->process($container); (new AutowirePass())->process($container);
$this->assertCount(3, $container->getDefinition('g')->getArguments()); $this->assertCount(3, $container->getDefinition('g')->getArguments());
$this->assertEquals('f', (string) $container->getDefinition('g')->getArgument(0)); $this->assertEquals(F::class, (string) $container->getDefinition('g')->getArgument(0));
$this->assertEquals('f', (string) $container->getDefinition('g')->getArgument(1)); $this->assertEquals(F::class, (string) $container->getDefinition('g')->getArgument(1));
$this->assertEquals('f', (string) $container->getDefinition('g')->getArgument(2)); $this->assertEquals(F::class, (string) $container->getDefinition('g')->getArgument(2));
} }
public function testCompleteExistingDefinition() public function testCompleteExistingDefinition()
@ -94,38 +102,38 @@ class AutowirePassTest extends TestCase
$container = new ContainerBuilder(); $container = new ContainerBuilder();
$container->register('b', __NAMESPACE__.'\B'); $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 = $container->register('h', __NAMESPACE__.'\H')->addArgument(new Reference('b'));
$hDefinition->setAutowired(true); $hDefinition->setAutowired(true);
$pass = new AutowirePass(); (new ResolveClassPass())->process($container);
$pass->process($container); (new AutowirePass())->process($container);
$this->assertCount(2, $container->getDefinition('h')->getArguments()); $this->assertCount(2, $container->getDefinition('h')->getArguments());
$this->assertEquals('b', (string) $container->getDefinition('h')->getArgument(0)); $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() public function testCompleteExistingDefinitionWithNotDefinedArguments()
{ {
$container = new ContainerBuilder(); $container = new ContainerBuilder();
$container->register('b', __NAMESPACE__.'\B'); $container->register(B::class);
$container->register('f', __NAMESPACE__.'\F'); $container->register(DInterface::class, F::class);
$hDefinition = $container->register('h', __NAMESPACE__.'\H')->addArgument('')->addArgument(''); $hDefinition = $container->register('h', __NAMESPACE__.'\H')->addArgument('')->addArgument('');
$hDefinition->setAutowired(true); $hDefinition->setAutowired(true);
$pass = new AutowirePass(); (new ResolveClassPass())->process($container);
$pass->process($container); (new AutowirePass())->process($container);
$this->assertCount(2, $container->getDefinition('h')->getArguments()); $this->assertCount(2, $container->getDefinition('h')->getArguments());
$this->assertEquals('b', (string) $container->getDefinition('h')->getArgument(0)); $this->assertEquals(B::class, (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));
} }
/** /**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException * @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() public function testTypeCollision()
{ {
@ -143,7 +151,7 @@ class AutowirePassTest extends TestCase
/** /**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException * @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() public function testTypeNotGuessable()
{ {
@ -160,7 +168,7 @@ class AutowirePassTest extends TestCase
/** /**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException * @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() public function testTypeNotGuessableWithSubclass()
{ {
@ -177,7 +185,7 @@ class AutowirePassTest extends TestCase
/** /**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException * @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() public function testTypeNotGuessableNoServicesFound()
{ {
@ -251,51 +259,51 @@ class AutowirePassTest extends TestCase
{ {
$container = new ContainerBuilder(); $container = new ContainerBuilder();
$container->setParameter('class_name', __NAMESPACE__.'\Foo'); $container->setParameter('class_name', Bar::class);
$container->register('foo', '%class_name%'); $container->register(Foo::class);
$barDefinition = $container->register('bar', __NAMESPACE__.'\Bar'); $barDefinition = $container->register('bar', '%class_name%');
$barDefinition->setAutowired(true); $barDefinition->setAutowired(true);
$pass = new AutowirePass(); (new ResolveClassPass())->process($container);
$pass->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() public function testOptionalParameter()
{ {
$container = new ContainerBuilder(); $container = new ContainerBuilder();
$container->register('a', __NAMESPACE__.'\A'); $container->register(A::class);
$container->register('foo', __NAMESPACE__.'\Foo'); $container->register(Foo::class);
$optDefinition = $container->register('opt', __NAMESPACE__.'\OptionalParameter'); $optDefinition = $container->register('opt', __NAMESPACE__.'\OptionalParameter');
$optDefinition->setAutowired(true); $optDefinition->setAutowired(true);
$pass = new AutowirePass(); (new ResolveClassPass())->process($container);
$pass->process($container); (new AutowirePass())->process($container);
$definition = $container->getDefinition('opt'); $definition = $container->getDefinition('opt');
$this->assertNull($definition->getArgument(0)); $this->assertNull($definition->getArgument(0));
$this->assertEquals('a', $definition->getArgument(1)); $this->assertEquals(A::class, $definition->getArgument(1));
$this->assertEquals('foo', $definition->getArgument(2)); $this->assertEquals(Foo::class, $definition->getArgument(2));
} }
public function testDontTriggerAutowiring() public function testDontTriggerAutowiring()
{ {
$container = new ContainerBuilder(); $container = new ContainerBuilder();
$container->register('foo', __NAMESPACE__.'\Foo'); $container->register(Foo::class);
$container->register('bar', __NAMESPACE__.'\Bar'); $container->register('bar', __NAMESPACE__.'\Bar');
$pass = new AutowirePass(); (new ResolveClassPass())->process($container);
$pass->process($container); (new AutowirePass())->process($container);
$this->assertCount(0, $container->getDefinition('bar')->getArguments()); $this->assertCount(0, $container->getDefinition('bar')->getArguments());
} }
/** /**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException * @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() public function testClassNotFoundThrowsException()
{ {
@ -310,7 +318,7 @@ class AutowirePassTest extends TestCase
/** /**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException * @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() public function testParentClassNotFoundThrowsException()
{ {
@ -323,28 +331,29 @@ class AutowirePassTest extends TestCase
$pass->process($container); $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() public function testDontUseAbstractServices()
{ {
$container = new ContainerBuilder(); $container = new ContainerBuilder();
$container->register('abstract_foo', __NAMESPACE__.'\Foo')->setAbstract(true); $container->register(Foo::class)->setAbstract(true);
$container->register('foo', __NAMESPACE__.'\Foo'); $container->register('foo', __NAMESPACE__.'\Foo');
$container->register('bar', __NAMESPACE__.'\Bar')->setAutowired(true); $container->register('bar', __NAMESPACE__.'\Bar')->setAutowired(true);
$pass = new AutowirePass(); (new ResolveClassPass())->process($container);
$pass->process($container); (new AutowirePass())->process($container);
$arguments = $container->getDefinition('bar')->getArguments();
$this->assertSame('foo', (string) $arguments[0]);
} }
public function testSomeSpecificArgumentsAreSet() public function testSomeSpecificArgumentsAreSet()
{ {
$container = new ContainerBuilder(); $container = new ContainerBuilder();
$container->register('foo', __NAMESPACE__.'\Foo'); $container->register('foo', Foo::class);
$container->register('a', __NAMESPACE__.'\A'); $container->register(A::class);
$container->register('dunglas', __NAMESPACE__.'\Dunglas'); $container->register(Dunglas::class);
$container->register('multiple', __NAMESPACE__.'\MultipleArguments') $container->register('multiple', __NAMESPACE__.'\MultipleArguments')
->setAutowired(true) ->setAutowired(true)
// set the 2nd (index 1) argument only: autowire the first and third // set the 2nd (index 1) argument only: autowire the first and third
@ -353,15 +362,15 @@ class AutowirePassTest extends TestCase
1 => new Reference('foo'), 1 => new Reference('foo'),
)); ));
$pass = new AutowirePass(); (new ResolveClassPass())->process($container);
$pass->process($container); (new AutowirePass())->process($container);
$definition = $container->getDefinition('multiple'); $definition = $container->getDefinition('multiple');
$this->assertEquals( $this->assertEquals(
array( array(
new Reference('a'), new Reference(A::class),
new Reference('foo'), new Reference('foo'),
new Reference('dunglas'), new Reference(Dunglas::class),
), ),
$definition->getArguments() $definition->getArguments()
); );
@ -369,34 +378,32 @@ class AutowirePassTest extends TestCase
/** /**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException * @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() public function testScalarArgsCannotBeAutowired()
{ {
$container = new ContainerBuilder(); $container = new ContainerBuilder();
$container->register('a', __NAMESPACE__.'\A'); $container->register(A::class);
$container->register('dunglas', __NAMESPACE__.'\Dunglas'); $container->register(Dunglas::class);
$container->register('arg_no_type_hint', __NAMESPACE__.'\MultipleArguments') $container->register('arg_no_type_hint', __NAMESPACE__.'\MultipleArguments')
->setAutowired(true); ->setAutowired(true);
$pass = new AutowirePass(); (new ResolveClassPass())->process($container);
$pass->process($container); (new AutowirePass())->process($container);
$container->getDefinition('arg_no_type_hint');
} }
public function testOptionalScalarNotReallyOptionalUsesDefaultValue() public function testOptionalScalarNotReallyOptionalUsesDefaultValue()
{ {
$container = new ContainerBuilder(); $container = new ContainerBuilder();
$container->register('a', __NAMESPACE__.'\A'); $container->register(A::class);
$container->register('lille', __NAMESPACE__.'\Lille'); $container->register(Lille::class);
$definition = $container->register('not_really_optional_scalar', __NAMESPACE__.'\MultipleArgumentsOptionalScalarNotReallyOptional') $definition = $container->register('not_really_optional_scalar', __NAMESPACE__.'\MultipleArgumentsOptionalScalarNotReallyOptional')
->setAutowired(true); ->setAutowired(true);
$pass = new AutowirePass(); (new ResolveClassPass())->process($container);
$pass->process($container); (new AutowirePass())->process($container);
$this->assertSame('default_val', $definition->getArgument(1)); $this->assertSame('default_val', $definition->getArgument(1));
} }
@ -405,21 +412,21 @@ class AutowirePassTest extends TestCase
{ {
$container = new ContainerBuilder(); $container = new ContainerBuilder();
$container->register('a', __NAMESPACE__.'\A'); $container->register(A::class);
$container->register('lille', __NAMESPACE__.'\Lille'); $container->register(Lille::class);
$container->register('with_optional_scalar', __NAMESPACE__.'\MultipleArgumentsOptionalScalar') $container->register('with_optional_scalar', __NAMESPACE__.'\MultipleArgumentsOptionalScalar')
->setAutowired(true); ->setAutowired(true);
$pass = new AutowirePass(); (new ResolveClassPass())->process($container);
$pass->process($container); (new AutowirePass())->process($container);
$definition = $container->getDefinition('with_optional_scalar'); $definition = $container->getDefinition('with_optional_scalar');
$this->assertEquals( $this->assertEquals(
array( array(
new Reference('a'), new Reference(A::class),
// use the default value // use the default value
'default_val', 'default_val',
new Reference('lille'), new Reference(Lille::class),
), ),
$definition->getArguments() $definition->getArguments()
); );
@ -429,19 +436,19 @@ class AutowirePassTest extends TestCase
{ {
$container = new ContainerBuilder(); $container = new ContainerBuilder();
$container->register('a', __NAMESPACE__.'\A'); $container->register(A::class);
$container->register('lille', __NAMESPACE__.'\Lille'); $container->register(Lille::class);
$container->register('with_optional_scalar_last', __NAMESPACE__.'\MultipleArgumentsOptionalScalarLast') $container->register('with_optional_scalar_last', __NAMESPACE__.'\MultipleArgumentsOptionalScalarLast')
->setAutowired(true); ->setAutowired(true);
$pass = new AutowirePass(); (new ResolveClassPass())->process($container);
$pass->process($container); (new AutowirePass())->process($container);
$definition = $container->getDefinition('with_optional_scalar_last'); $definition = $container->getDefinition('with_optional_scalar_last');
$this->assertEquals( $this->assertEquals(
array( array(
new Reference('a'), new Reference(A::class),
new Reference('lille'), new Reference(Lille::class),
), ),
$definition->getArguments() $definition->getArguments()
); );
@ -450,10 +457,10 @@ class AutowirePassTest extends TestCase
public function testSetterInjection() public function testSetterInjection()
{ {
$container = new ContainerBuilder(); $container = new ContainerBuilder();
$container->register('app_foo', Foo::class); $container->register(Foo::class);
$container->register('app_a', A::class); $container->register(A::class);
$container->register('app_collision_a', CollisionA::class); $container->register(CollisionA::class);
$container->register('app_collision_b', CollisionB::class); $container->register(CollisionB::class);
// manually configure *one* call, to override autowiring // manually configure *one* call, to override autowiring
$container $container
@ -462,8 +469,8 @@ class AutowirePassTest extends TestCase
->addMethodCall('setWithCallsConfigured', array('manual_arg1', 'manual_arg2')) ->addMethodCall('setWithCallsConfigured', array('manual_arg1', 'manual_arg2'))
; ;
$pass = new AutowirePass(); (new ResolveClassPass())->process($container);
$pass->process($container); (new AutowirePass())->process($container);
$methodCalls = $container->getDefinition('setter_injection')->getMethodCalls(); $methodCalls = $container->getDefinition('setter_injection')->getMethodCalls();
@ -479,7 +486,7 @@ class AutowirePassTest extends TestCase
); );
// test setFoo args // test setFoo args
$this->assertEquals( $this->assertEquals(
array(new Reference('app_foo')), array(new Reference(Foo::class)),
$methodCalls[1][1] $methodCalls[1][1]
); );
} }
@ -487,10 +494,10 @@ class AutowirePassTest extends TestCase
public function testExplicitMethodInjection() public function testExplicitMethodInjection()
{ {
$container = new ContainerBuilder(); $container = new ContainerBuilder();
$container->register('app_foo', Foo::class); $container->register(Foo::class);
$container->register('app_a', A::class); $container->register(A::class);
$container->register('app_collision_a', CollisionA::class); $container->register(CollisionA::class);
$container->register('app_collision_b', CollisionB::class); $container->register(CollisionB::class);
$container $container
->register('setter_injection', SetterInjection::class) ->register('setter_injection', SetterInjection::class)
@ -498,8 +505,8 @@ class AutowirePassTest extends TestCase
->addMethodCall('notASetter', array()) ->addMethodCall('notASetter', array())
; ;
$pass = new AutowirePass(); (new ResolveClassPass())->process($container);
$pass->process($container); (new AutowirePass())->process($container);
$methodCalls = $container->getDefinition('setter_injection')->getMethodCalls(); $methodCalls = $container->getDefinition('setter_injection')->getMethodCalls();
@ -508,7 +515,7 @@ class AutowirePassTest extends TestCase
array_column($methodCalls, 0) array_column($methodCalls, 0)
); );
$this->assertEquals( $this->assertEquals(
array(new Reference('app_a')), array(new Reference(A::class)),
$methodCalls[0][1] $methodCalls[0][1]
); );
} }
@ -519,7 +526,6 @@ class AutowirePassTest extends TestCase
$container $container
->register('bar', Bar::class) ->register('bar', Bar::class)
->setAutowired(true)
->setProperty('a', array(new TypedReference(A::class, A::class))) ->setProperty('a', array(new TypedReference(A::class, A::class)))
; ;
@ -580,7 +586,7 @@ class AutowirePassTest extends TestCase
/** /**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException * @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() public function testSetterInjectionCollisionThrowsException()
{ {
@ -595,6 +601,10 @@ class AutowirePassTest extends TestCase
$pass->process($container); $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() public function testProcessDoesNotTriggerDeprecations()
{ {
$container = new ContainerBuilder(); $container = new ContainerBuilder();
@ -610,31 +620,31 @@ class AutowirePassTest extends TestCase
{ {
$container = new ContainerBuilder(); $container = new ContainerBuilder();
$container->register('a', __NAMESPACE__.'\A'); $container->register(A::class);
$container->register('lille', __NAMESPACE__.'\Lille'); $container->register(Lille::class);
$container->register('foo', __NAMESPACE__.'\MultipleArgumentsOptionalScalar') $container->register('foo', __NAMESPACE__.'\MultipleArgumentsOptionalScalar')
->setAutowired(true) ->setAutowired(true)
->setArguments(array('', '')); ->setArguments(array('', ''));
$pass = new AutowirePass(); (new ResolveClassPass())->process($container);
$pass->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() public function testWithFactory()
{ {
$container = new ContainerBuilder(); $container = new ContainerBuilder();
$container->register('foo', Foo::class); $container->register(Foo::class);
$definition = $container->register('a', A::class) $definition = $container->register('a', A::class)
->setFactory(array(A::class, 'create')) ->setFactory(array(A::class, 'create'))
->setAutowired(true); ->setAutowired(true);
$pass = new AutowirePass(); (new ResolveClassPass())->process($container);
$pass->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 @@ class AutowirePassTest extends TestCase
$foo->addMethodCall($method, array()); $foo->addMethodCall($method, array());
} }
$pass = new AutowirePass();
if (method_exists($this, 'expectException')) { if (method_exists($this, 'expectException')) {
$this->expectException(RuntimeException::class); $this->expectException(RuntimeException::class);
$this->expectExceptionMessage($expectedMsg); $this->expectExceptionMessage($expectedMsg);
@ -665,68 +673,21 @@ class AutowirePassTest extends TestCase
$this->setExpectedException(RuntimeException::class, $expectedMsg); $this->setExpectedException(RuntimeException::class, $expectedMsg);
} }
$pass->process($container); (new ResolveClassPass())->process($container);
(new AutowirePass())->process($container);
} }
public function provideNotWireableCalls() public function provideNotWireableCalls()
{ {
return array( 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.'), array(null, 'Cannot autowire service "foo": method "Symfony\Component\DependencyInjection\Tests\Compiler\NotWireable::setProtectedMethod()" must be public.'),
); );
} }
/** /**
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException * @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". * @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 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".
*/ */
public function testByIdAlternative() public function testByIdAlternative()
{ {
@ -735,7 +696,7 @@ class AutowirePassTest extends TestCase
$container->setAlias(IInterface::class, 'i'); $container->setAlias(IInterface::class, 'i');
$container->register('i', I::class); $container->register('i', I::class);
$container->register('j', J::class) $container->register('j', J::class)
->setAutowired(Definition::AUTOWIRE_BY_ID); ->setAutowired(true);
$pass = new AutowirePass(); $pass = new AutowirePass();
$pass->process($container); $pass->process($container);

View File

@ -71,7 +71,6 @@ class RegisterServiceSubscribersPassTest extends TestCase
$foo = $container->getDefinition('foo'); $foo = $container->getDefinition('foo');
$locator = $container->getDefinition((string) $foo->getArgument(0)); $locator = $container->getDefinition((string) $foo->getArgument(0));
$this->assertFalse($locator->isAutowired());
$this->assertFalse($locator->isPublic()); $this->assertFalse($locator->isPublic());
$this->assertSame(ServiceLocator::class, $locator->getClass()); $this->assertSame(ServiceLocator::class, $locator->getClass());
@ -102,7 +101,6 @@ class RegisterServiceSubscribersPassTest extends TestCase
$foo = $container->getDefinition('foo'); $foo = $container->getDefinition('foo');
$locator = $container->getDefinition((string) $foo->getArgument(0)); $locator = $container->getDefinition((string) $foo->getArgument(0));
$this->assertTrue($locator->isAutowired());
$this->assertFalse($locator->isPublic()); $this->assertFalse($locator->isPublic());
$this->assertSame(ServiceLocator::class, $locator->getClass()); $this->assertSame(ServiceLocator::class, $locator->getClass());

View File

@ -967,13 +967,13 @@ class ContainerBuilderTest extends TestCase
{ {
$container = new ContainerBuilder(); $container = new ContainerBuilder();
$container->register('a', __NAMESPACE__.'\A'); $container->register(A::class);
$bDefinition = $container->register('b', __NAMESPACE__.'\B'); $bDefinition = $container->register('b', __NAMESPACE__.'\B');
$bDefinition->setAutowired(true); $bDefinition->setAutowired(true);
$container->compile(); $container->compile();
$this->assertEquals('a', (string) $container->getDefinition('b')->getArgument(0)); $this->assertEquals(A::class, (string) $container->getDefinition('b')->getArgument(0));
} }
public function testClosureProxy() public function testClosureProxy()

View File

@ -70,7 +70,7 @@ class ProjectServiceContainer extends Container
* This service is shared. * This service is shared.
* This method always returns the same instance of the service. * 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 * @return \Foo A Foo instance
*/ */

View File

@ -91,7 +91,7 @@ class ProjectServiceContainer extends Container
* This service is shared. * This service is shared.
* This method always returns the same instance of the service. * 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 * @return \TestServiceSubscriber A TestServiceSubscriber instance
*/ */
@ -118,7 +118,7 @@ class ProjectServiceContainer extends Container
* If you want to be able to request this service from the container directly, * 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. * 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 * @return \stdClass A stdClass instance
*/ */

View File

@ -2,7 +2,7 @@
<container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> <container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services> <services>
<service id="service_container" class="Symfony\Component\DependencyInjection\ContainerInterface" synthetic="true"/> <service id="service_container" class="Symfony\Component\DependencyInjection\ContainerInterface" synthetic="true"/>
<service id="foo" class="Foo" autowire="by-type"/> <service id="foo" class="Foo" autowire="true"/>
<service id="Psr\Container\ContainerInterface" alias="service_container" public="false"/> <service id="Psr\Container\ContainerInterface" alias="service_container" public="false"/>
<service id="Symfony\Component\DependencyInjection\ContainerInterface" alias="service_container" public="false"/> <service id="Symfony\Component\DependencyInjection\ContainerInterface" alias="service_container" public="false"/>
</services> </services>

View File

@ -5,7 +5,7 @@ services:
synthetic: true synthetic: true
foo: foo:
class: Foo class: Foo
autowire: by_type autowire: true
Psr\Container\ContainerInterface: Psr\Container\ContainerInterface:
alias: service_container alias: service_container
public: false public: false

View File

@ -52,7 +52,6 @@ class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface
continue; continue;
} }
$class = $def->getClass(); $class = $def->getClass();
$autowired = $def->getAutowired();
// resolve service class, taking parent definitions into account // resolve service class, taking parent definitions into account
while (!$class && $def instanceof ChildDefinition) { while (!$class && $def instanceof ChildDefinition) {
@ -129,7 +128,7 @@ class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface
} }
// register the maps as a per-method service-locators // register the maps as a per-method service-locators
if ($args) { if ($args) {
$controllers[$id.':'.$r->name] = ServiceLocatorTagPass::register($container, $args, $autowired); $controllers[$id.':'.$r->name] = ServiceLocatorTagPass::register($container, $args);
} }
} }
} }

View File

@ -12,6 +12,7 @@
namespace Symfony\Component\HttpKernel\Tests\DependencyInjection; namespace Symfony\Component\HttpKernel\Tests\DependencyInjection;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\DependencyInjection\FragmentRendererPass; use Symfony\Component\HttpKernel\DependencyInjection\FragmentRendererPass;
@ -58,11 +59,7 @@ class FragmentRendererPassTest extends TestCase
'my_content_renderer' => array(array('alias' => 'foo')), 'my_content_renderer' => array(array('alias' => 'foo')),
); );
$renderer = $this->getMockBuilder('Symfony\Component\DependencyInjection\Definition')->getMock(); $renderer = new Definition('', array(null));
$renderer
->expects($this->once())
->method('replaceArgument')
->with(0, $this->equalTo(new Reference('service_locator.5ae0a401097c64ca63ed976c71bc9642')));
$definition = $this->getMockBuilder('Symfony\Component\DependencyInjection\Definition')->getMock(); $definition = $this->getMockBuilder('Symfony\Component\DependencyInjection\Definition')->getMock();
$definition->expects($this->atLeastOnce()) $definition->expects($this->atLeastOnce())
@ -90,6 +87,8 @@ class FragmentRendererPassTest extends TestCase
$pass = new FragmentRendererPass(); $pass = new FragmentRendererPass();
$pass->process($builder); $pass->process($builder);
$this->assertInstanceOf(Reference::class, $renderer->getArgument(0));
} }
} }

View File

@ -15,7 +15,6 @@ use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ServiceLocator; use Symfony\Component\DependencyInjection\ServiceLocator;
use Symfony\Component\DependencyInjection\TypedReference; use Symfony\Component\DependencyInjection\TypedReference;
use Symfony\Component\HttpKernel\DependencyInjection\RegisterControllerArgumentLocatorsPass; use Symfony\Component\HttpKernel\DependencyInjection\RegisterControllerArgumentLocatorsPass;
@ -130,7 +129,6 @@ class RegisterControllerArgumentLocatorsPassTest extends TestCase
$resolver = $container->register('argument_resolver.service')->addArgument(array()); $resolver = $container->register('argument_resolver.service')->addArgument(array());
$container->register('foo', RegisterTestController::class) $container->register('foo', RegisterTestController::class)
->setAutowired(true)
->addTag('controller.service_arguments') ->addTag('controller.service_arguments')
; ;
@ -139,13 +137,13 @@ class RegisterControllerArgumentLocatorsPassTest extends TestCase
$locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0); $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]); $locator = $container->getDefinition((string) $locator['foo:fooAction']->getValues()[0]);
$this->assertSame(ServiceLocator::class, $locator->getClass()); $this->assertSame(ServiceLocator::class, $locator->getClass());
$this->assertFalse($locator->isPublic()); $this->assertFalse($locator->isPublic());
$this->assertTrue($locator->isAutowired());
$expected = array('bar' => new ServiceClosureArgument(new TypedReference('stdClass', 'stdClass', ContainerInterface::IGNORE_ON_INVALID_REFERENCE, false))); $expected = array('bar' => new ServiceClosureArgument(new TypedReference('stdClass', 'stdClass', ContainerInterface::IGNORE_ON_INVALID_REFERENCE, false)));
$this->assertEquals($expected, $locator->getArgument(0)); $this->assertEquals($expected, $locator->getArgument(0));
@ -166,7 +164,6 @@ class RegisterControllerArgumentLocatorsPassTest extends TestCase
$locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0); $locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0);
$locator = $container->getDefinition((string) $locator['foo:fooAction']->getValues()[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))); $expected = array('bar' => new ServiceClosureArgument(new TypedReference('bar', 'stdClass', ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, false)));
$this->assertEquals($expected, $locator->getArgument(0)); $this->assertEquals($expected, $locator->getArgument(0));

View File

@ -12,7 +12,6 @@
namespace Symfony\Component\HttpKernel\Tests\DependencyInjection; namespace Symfony\Component\HttpKernel\Tests\DependencyInjection;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
use Symfony\Component\DependencyInjection\Compiler\ResolveInvalidReferencesPass; use Symfony\Component\DependencyInjection\Compiler\ResolveInvalidReferencesPass;
use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\Reference;
@ -74,10 +73,10 @@ class RemoveEmptyControllerArgumentLocatorsPassTest extends TestCase
(new RemoveEmptyControllerArgumentLocatorsPass())->process($container); (new RemoveEmptyControllerArgumentLocatorsPass())->process($container);
$expected = array( $expected = array(
RegisterTestController::class.':fooAction' => new ServiceClosureArgument(new Reference('service_locator.37b6201ea2e9e6ade00ab09ae7a6ceb3')), RegisterTestController::class.':fooAction',
RegisterTestController::class.'::fooAction' => new ServiceClosureArgument(new Reference('service_locator.37b6201ea2e9e6ade00ab09ae7a6ceb3')), 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)));
} }
} }