[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
-------------------
* [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.

View File

@ -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.

View File

@ -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) {

View File

@ -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) {

View File

@ -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));

View File

@ -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();

View File

@ -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.

View File

@ -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)

View File

@ -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);

View File

@ -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();

View File

@ -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)))) {

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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) {

View File

@ -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 = '';

View File

@ -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.
*

View File

@ -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);
}

View File

@ -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>

View File

@ -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);

View File

@ -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());

View File

@ -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()

View File

@ -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
*/

View File

@ -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
*/

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">
<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>

View File

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

View File

@ -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);
}
}
}

View File

@ -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));
}
}

View File

@ -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));

View File

@ -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)));
}
}