feature #22295 [BC BREAK][DI] Always autowire "by id" instead of using reflection against all existing services (nicolas-grekas)
This PR was merged into the 3.3-dev branch.
Discussion
----------
[BC BREAK][DI] Always autowire "by id" instead of using reflection against all existing services
| Q | A
| ------------- | ---
| Branch? | 3.3
| Bug fix? | no
| New feature? | yes
| BC breaks? | yes - compile time only
| Deprecations? | no
| Tests pass? | yes
| Fixed tickets | -
| License | MIT
| Doc PR | -
(patch best reviewed [ignoring whitespaces](https://github.com/symfony/symfony/pull/22295/files?w=1).)
"By-id" autowiring, as introduced in #22060 is free from all the issues that "by-type" autowiring has:
- it has no magic and requires explicit type<>id matching (*vs* using reflection on all services to cherry-pick *the* one that matches some type-hint *at that time*, which is fragile)
- it is free from any ambiguities (*vs* the Damocles' sword of breaking config just by enabling some unrelated bundle)
- it is easily introspected: just look at DI config files (*vs* inspecting the type-hierarchy of all services + their type-hints)
- ~~it is side-effect free, thus plain predictable (*vs* auto-registration of discovered types as services)~~
- it plays nice with deprecated services or classes (see #22282)
- *etc.*
Another consideration is that any "by-type" autowired configuration is either broken (because of future ambiguities) - or equivalent to a "by-id" configuration (because resolving ambiguities *means* adding explicit type<>id mappings.) For theoreticians, we could say that "by-id" autowiring is the asymptotic limit of "by-type" autowiring :-)
For all these reasons - and also because it reduces the complexity of the code base - I propose to change the behavior and only support "by-id" autowiring in 3.3. This will break some configurations relying on "by-type" autowiring. Yet the break will only happen at compile-time, which means this won't *silently* break any apps. For all core Symfony services, they will work out of the box thanks to #22098 *et al.* For the remaining services, fixing ones config should be pretty straightforward: just follow the suggestions provided by the exception messages. If they are fine to you, you'll end up with the exact same config in the end. And maybe you'll spot issues that were hidden previously.
Commits
-------
cc5e582dcf
[BC BREAK][DI] Always autowire "by id" instead of using reflection against all existing services
This commit is contained in:
commit
ab93feae3f
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -221,7 +221,7 @@ class JsonDescriptor extends Descriptor
|
||||
'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) {
|
||||
|
@ -182,7 +182,7 @@ class MarkdownDescriptor extends Descriptor
|
||||
."\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) {
|
||||
|
@ -295,7 +295,7 @@ class TextDescriptor extends Descriptor
|
||||
$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));
|
||||
|
@ -371,7 +371,7 @@ class XmlDescriptor extends Descriptor
|
||||
$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();
|
||||
|
@ -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.
|
||||
|
@ -31,7 +31,6 @@ class AutowirePass extends AbstractRecursivePass
|
||||
private $types;
|
||||
private $ambiguousServiceTypes = array();
|
||||
private $autowired = array();
|
||||
private $currentDefinition;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
@ -77,7 +76,7 @@ class AutowirePass extends AbstractRecursivePass
|
||||
*/
|
||||
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 @@ class AutowirePass extends AbstractRecursivePass
|
||||
if (!$value instanceof Definition) {
|
||||
return parent::processValue($value, $isRoot);
|
||||
}
|
||||
|
||||
$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();
|
||||
|
||||
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);
|
||||
}
|
||||
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);
|
||||
} 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];
|
||||
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 @@ class AutowirePass extends AbstractRecursivePass
|
||||
|
||||
// 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 @@ class AutowirePass extends AbstractRecursivePass
|
||||
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 @@ class AutowirePass extends AbstractRecursivePass
|
||||
|
||||
/**
|
||||
* @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 @@ class AutowirePass extends AbstractRecursivePass
|
||||
$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 @@ class AutowirePass extends AbstractRecursivePass
|
||||
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 @@ class AutowirePass extends AbstractRecursivePass
|
||||
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 @@ class AutowirePass extends AbstractRecursivePass
|
||||
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 @@ class AutowirePass extends AbstractRecursivePass
|
||||
|
||||
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)
|
||||
|
@ -38,9 +38,11 @@ class RegisterServiceSubscribersPass extends AbstractRecursivePass
|
||||
}
|
||||
|
||||
$serviceMap = array();
|
||||
$autowire = $value->isAutowired();
|
||||
|
||||
foreach ($value->getTag('container.service_subscriber') as $attributes) {
|
||||
if (!$attributes) {
|
||||
$autowire = true;
|
||||
continue;
|
||||
}
|
||||
ksort($attributes);
|
||||
@ -82,6 +84,9 @@ class RegisterServiceSubscribersPass extends AbstractRecursivePass
|
||||
$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 @@ class RegisterServiceSubscribersPass extends AbstractRecursivePass
|
||||
}
|
||||
|
||||
$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);
|
||||
|
@ -100,7 +100,7 @@ class ResolveDefinitionTemplatesPass extends AbstractRecursivePass
|
||||
$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 @@ class ResolveDefinitionTemplatesPass extends AbstractRecursivePass
|
||||
$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();
|
||||
|
@ -75,11 +75,10 @@ final class ServiceLocatorTagPass extends AbstractRecursivePass
|
||||
/**
|
||||
* @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 @@ final class ServiceLocatorTagPass extends AbstractRecursivePass
|
||||
$locator = (new Definition(ServiceLocator::class))
|
||||
->addArgument($refMap)
|
||||
->setPublic(false)
|
||||
->setAutowired($autowired)
|
||||
->addTag('container.service_locator');
|
||||
|
||||
if (!$container->has($id = 'service_locator.'.md5(serialize($locator)))) {
|
||||
|
@ -21,9 +21,6 @@ use Symfony\Component\DependencyInjection\Exception\OutOfBoundsException;
|
||||
*/
|
||||
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 @@ class Definition
|
||||
* @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 @@ class Definition
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
@ -646,11 +646,10 @@ EOF;
|
||||
}
|
||||
|
||||
if ($definition->isAutowired()) {
|
||||
$autowired = Definition::AUTOWIRE_BY_TYPE === $definition->getAutowired() ? 'types' : 'ids';
|
||||
$doc .= <<<EOF
|
||||
|
||||
*
|
||||
* This service is autowired by {$autowired}.
|
||||
* This service is autowired.
|
||||
EOF;
|
||||
}
|
||||
|
||||
|
@ -195,7 +195,7 @@ class XmlDumper extends Dumper
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -106,7 +106,7 @@ class YamlDumper extends Dumper
|
||||
}
|
||||
|
||||
if ($definition->isAutowired()) {
|
||||
$code .= sprintf(" autowire: %s\n", Definition::AUTOWIRE_BY_TYPE === $definition->getAutowired() ? 'by_type' : 'by_id');
|
||||
$code .= " autowire: true\n";
|
||||
}
|
||||
|
||||
$autowiringTypesCode = '';
|
||||
|
@ -172,7 +172,7 @@ class XmlFileLoader extends FileLoader
|
||||
}
|
||||
}
|
||||
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 @@ class XmlFileLoader extends FileLoader
|
||||
}
|
||||
|
||||
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 @@ 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.
|
||||
*
|
||||
|
@ -486,14 +486,6 @@ class YamlFileLoader extends FileLoader
|
||||
|
||||
$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);
|
||||
}
|
||||
|
||||
|
@ -102,7 +102,7 @@
|
||||
<xsd:element name="tag" type="tag" minOccurs="0" maxOccurs="unbounded" />
|
||||
</xsd:choice>
|
||||
<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:complexType>
|
||||
|
||||
@ -130,7 +130,7 @@
|
||||
<xsd:attribute name="decorates" type="xsd:string" />
|
||||
<xsd:attribute name="decoration-inner-name" type="xsd:string" />
|
||||
<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:complexType>
|
||||
|
||||
@ -149,7 +149,7 @@
|
||||
<xsd:attribute name="public" type="boolean" />
|
||||
<xsd:attribute name="lazy" type="boolean" />
|
||||
<xsd:attribute name="abstract" type="boolean" />
|
||||
<xsd:attribute name="autowire" type="autowire" />
|
||||
<xsd:attribute name="autowire" type="boolean" />
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="prototype">
|
||||
@ -169,7 +169,7 @@
|
||||
<xsd:attribute name="lazy" type="boolean" />
|
||||
<xsd:attribute name="abstract" type="boolean" />
|
||||
<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:complexType>
|
||||
|
||||
@ -263,10 +263,4 @@
|
||||
<xsd:pattern value="(%.+%|true|false)" />
|
||||
</xsd:restriction>
|
||||
</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>
|
||||
|
@ -13,8 +13,8 @@ namespace Symfony\Component\DependencyInjection\Tests\Compiler;
|
||||
|
||||
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 @@ class AutowirePassTest extends TestCase
|
||||
{
|
||||
$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 @@ class AutowirePassTest extends TestCase
|
||||
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 @@ class AutowirePassTest extends TestCase
|
||||
$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 @@ class AutowirePassTest extends TestCase
|
||||
|
||||
/**
|
||||
* @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 @@ class AutowirePassTest extends TestCase
|
||||
|
||||
/**
|
||||
* @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 @@ class AutowirePassTest extends TestCase
|
||||
|
||||
/**
|
||||
* @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 @@ class AutowirePassTest extends TestCase
|
||||
{
|
||||
$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 @@ class AutowirePassTest extends TestCase
|
||||
|
||||
/**
|
||||
* @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 @@ class AutowirePassTest extends TestCase
|
||||
$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 @@ class AutowirePassTest extends TestCase
|
||||
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 @@ class AutowirePassTest extends TestCase
|
||||
|
||||
/**
|
||||
* @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 @@ class AutowirePassTest extends TestCase
|
||||
{
|
||||
$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 @@ class AutowirePassTest extends TestCase
|
||||
{
|
||||
$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 @@ class AutowirePassTest extends TestCase
|
||||
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 @@ class AutowirePassTest extends TestCase
|
||||
->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 @@ class AutowirePassTest extends TestCase
|
||||
);
|
||||
// test setFoo args
|
||||
$this->assertEquals(
|
||||
array(new Reference('app_foo')),
|
||||
array(new Reference(Foo::class)),
|
||||
$methodCalls[1][1]
|
||||
);
|
||||
}
|
||||
@ -487,10 +494,10 @@ class AutowirePassTest extends TestCase
|
||||
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 @@ class AutowirePassTest extends TestCase
|
||||
->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 @@ class AutowirePassTest extends TestCase
|
||||
array_column($methodCalls, 0)
|
||||
);
|
||||
$this->assertEquals(
|
||||
array(new Reference('app_a')),
|
||||
array(new Reference(A::class)),
|
||||
$methodCalls[0][1]
|
||||
);
|
||||
}
|
||||
@ -519,7 +526,6 @@ class AutowirePassTest extends TestCase
|
||||
|
||||
$container
|
||||
->register('bar', Bar::class)
|
||||
->setAutowired(true)
|
||||
->setProperty('a', array(new TypedReference(A::class, A::class)))
|
||||
;
|
||||
|
||||
@ -580,7 +586,7 @@ class AutowirePassTest extends TestCase
|
||||
|
||||
/**
|
||||
* @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 @@ class AutowirePassTest extends TestCase
|
||||
$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 @@ class AutowirePassTest extends TestCase
|
||||
{
|
||||
$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 @@ class AutowirePassTest extends TestCase
|
||||
$foo->addMethodCall($method, array());
|
||||
}
|
||||
|
||||
$pass = new AutowirePass();
|
||||
|
||||
if (method_exists($this, 'expectException')) {
|
||||
$this->expectException(RuntimeException::class);
|
||||
$this->expectExceptionMessage($expectedMsg);
|
||||
@ -665,68 +673,21 @@ class AutowirePassTest extends TestCase
|
||||
$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 @@ class AutowirePassTest extends TestCase
|
||||
$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);
|
||||
|
@ -71,7 +71,6 @@ class RegisterServiceSubscribersPassTest extends TestCase
|
||||
$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 @@ class RegisterServiceSubscribersPassTest extends TestCase
|
||||
$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());
|
||||
|
||||
|
@ -967,13 +967,13 @@ class ContainerBuilderTest extends TestCase
|
||||
{
|
||||
$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()
|
||||
|
@ -70,7 +70,7 @@ class ProjectServiceContainer extends Container
|
||||
* 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
|
||||
*/
|
||||
|
@ -91,7 +91,7 @@ class ProjectServiceContainer extends Container
|
||||
* 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 @@ class ProjectServiceContainer extends Container
|
||||
* 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
|
||||
*/
|
||||
|
@ -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">
|
||||
<services>
|
||||
<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="Symfony\Component\DependencyInjection\ContainerInterface" alias="service_container" public="false"/>
|
||||
</services>
|
||||
|
@ -5,7 +5,7 @@ services:
|
||||
synthetic: true
|
||||
foo:
|
||||
class: Foo
|
||||
autowire: by_type
|
||||
autowire: true
|
||||
Psr\Container\ContainerInterface:
|
||||
alias: service_container
|
||||
public: false
|
||||
|
@ -52,7 +52,6 @@ class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface
|
||||
continue;
|
||||
}
|
||||
$class = $def->getClass();
|
||||
$autowired = $def->getAutowired();
|
||||
|
||||
// resolve service class, taking parent definitions into account
|
||||
while (!$class && $def instanceof ChildDefinition) {
|
||||
@ -129,7 +128,7 @@ class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface
|
||||
}
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 @@ class FragmentRendererPassTest extends TestCase
|
||||
'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 @@ class FragmentRendererPassTest extends TestCase
|
||||
|
||||
$pass = new FragmentRendererPass();
|
||||
$pass->process($builder);
|
||||
|
||||
$this->assertInstanceOf(Reference::class, $renderer->getArgument(0));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,6 @@ use PHPUnit\Framework\TestCase;
|
||||
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 @@ class RegisterControllerArgumentLocatorsPassTest extends TestCase
|
||||
$resolver = $container->register('argument_resolver.service')->addArgument(array());
|
||||
|
||||
$container->register('foo', RegisterTestController::class)
|
||||
->setAutowired(true)
|
||||
->addTag('controller.service_arguments')
|
||||
;
|
||||
|
||||
@ -139,13 +137,13 @@ class RegisterControllerArgumentLocatorsPassTest extends TestCase
|
||||
|
||||
$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 @@ class RegisterControllerArgumentLocatorsPassTest extends TestCase
|
||||
|
||||
$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));
|
||||
|
@ -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 @@ class RemoveEmptyControllerArgumentLocatorsPassTest extends TestCase
|
||||
(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)));
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user