feature #20167 [DependencyInjection] Make method (setter) autowiring configurable (dunglas)
This PR was merged into the 3.3-dev branch.
Discussion
----------
[DependencyInjection] Make method (setter) autowiring configurable
| Q | A |
| --- | --- |
| Branch? | master |
| Bug fix? | no |
| New feature? | yes |
| BC breaks? | no |
| Deprecations? | maybe? |
| Tests pass? | yes |
| Fixed tickets | #19631 |
| License | MIT |
| Doc PR | symfony/symfony-docs#7041 |
Follow up of #19631. Implements https://github.com/symfony/symfony/pull/19631#issuecomment-240646169:
Edit: the last supported format:
``` yaml
services:
foo:
class: Foo
autowire: ['__construct', 'set*'] # Autowire constructor and all setters
autowire: true # Converted by loaders in `autowire: ['__construct']` for BC
autowire: ['foo', 'bar'] # Autowire only `foo` and `bar` methods
```
Outdated:
``` yaml
autowire: true # constructor autowiring
autowire: [__construct, setFoo, setBar] # autowire whitelisted methods only
autowire: '*' # autowire constructor + every setters (following existing rules for setters autowiring)
```
- [x] Allow to specify the list of methods in the XML loader
- [x] Add tests for the YAML loader
Commits
-------
6dd53c7
[DependencyInjection] Introduce method injection for autowiring
This commit is contained in:
commit
69dcf41a3c
@ -24,6 +24,9 @@ use Symfony\Component\DependencyInjection\Reference;
|
||||
*/
|
||||
class AutowirePass implements CompilerPassInterface
|
||||
{
|
||||
/**
|
||||
* @var ContainerBuilder
|
||||
*/
|
||||
private $container;
|
||||
private $reflectionClasses = array();
|
||||
private $definedTypes = array();
|
||||
@ -41,8 +44,8 @@ class AutowirePass implements CompilerPassInterface
|
||||
try {
|
||||
$this->container = $container;
|
||||
foreach ($container->getDefinitions() as $id => $definition) {
|
||||
if ($definition->isAutowired()) {
|
||||
$this->completeDefinition($id, $definition);
|
||||
if ($autowiredMethods = $definition->getAutowiredMethods()) {
|
||||
$this->completeDefinition($id, $definition, $autowiredMethods);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
@ -72,9 +75,11 @@ class AutowirePass implements CompilerPassInterface
|
||||
$metadata['__construct'] = self::getResourceMetadataForMethod($constructor);
|
||||
}
|
||||
|
||||
foreach (self::getSetters($reflectionClass) as $reflectionMethod) {
|
||||
foreach ($reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $reflectionMethod) {
|
||||
if (!$reflectionMethod->isStatic()) {
|
||||
$metadata[$reflectionMethod->name] = self::getResourceMetadataForMethod($reflectionMethod);
|
||||
}
|
||||
}
|
||||
|
||||
return new AutowireServiceResource($reflectionClass->name, $reflectionClass->getFileName(), $metadata);
|
||||
}
|
||||
@ -84,10 +89,11 @@ class AutowirePass implements CompilerPassInterface
|
||||
*
|
||||
* @param string $id
|
||||
* @param Definition $definition
|
||||
* @param string[] $autowiredMethods
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
private function completeDefinition($id, Definition $definition)
|
||||
private function completeDefinition($id, Definition $definition, array $autowiredMethods)
|
||||
{
|
||||
if (!$reflectionClass = $this->getReflectionClass($id, $definition)) {
|
||||
return;
|
||||
@ -97,12 +103,75 @@ class AutowirePass implements CompilerPassInterface
|
||||
$this->container->addResource(static::createResourceForClass($reflectionClass));
|
||||
}
|
||||
|
||||
if (!$constructor = $reflectionClass->getConstructor()) {
|
||||
return;
|
||||
$methodsCalled = array();
|
||||
foreach ($definition->getMethodCalls() as $methodCall) {
|
||||
$methodsCalled[$methodCall[0]] = true;
|
||||
}
|
||||
|
||||
foreach ($this->getMethodsToAutowire($id, $reflectionClass, $autowiredMethods) as $reflectionMethod) {
|
||||
if (!isset($methodsCalled[$reflectionMethod->name])) {
|
||||
$this->autowireMethod($id, $definition, $reflectionMethod);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of methods to autowire.
|
||||
*
|
||||
* @param string $id
|
||||
* @param \ReflectionClass $reflectionClass
|
||||
* @param string[] $autowiredMethods
|
||||
*
|
||||
* @return \ReflectionMethod[]
|
||||
*/
|
||||
private function getMethodsToAutowire($id, \ReflectionClass $reflectionClass, array $autowiredMethods)
|
||||
{
|
||||
$found = array();
|
||||
$regexList = array();
|
||||
foreach ($autowiredMethods as $pattern) {
|
||||
$regexList[] = '/^'.str_replace('\*', '.*', preg_quote($pattern, '/')).'$/i';
|
||||
}
|
||||
|
||||
foreach ($reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $reflectionMethod) {
|
||||
if ($reflectionMethod->isStatic()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($regexList as $k => $regex) {
|
||||
if (preg_match($regex, $reflectionMethod->name)) {
|
||||
$found[] = $autowiredMethods[$k];
|
||||
yield $reflectionMethod;
|
||||
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($notFound = array_diff($autowiredMethods, $found)) {
|
||||
$compiler = $this->container->getCompiler();
|
||||
$compiler->addLogMessage($compiler->getLoggingFormatter()->formatUnusedAutowiringPatterns($this, $id, $notFound));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Autowires the constructor or a setter.
|
||||
*
|
||||
* @param string $id
|
||||
* @param Definition $definition
|
||||
* @param \ReflectionMethod $reflectionMethod
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
private function autowireMethod($id, Definition $definition, \ReflectionMethod $reflectionMethod)
|
||||
{
|
||||
if ($isConstructor = $reflectionMethod->isConstructor()) {
|
||||
$arguments = $definition->getArguments();
|
||||
foreach ($constructor->getParameters() as $index => $parameter) {
|
||||
} else {
|
||||
$arguments = array();
|
||||
}
|
||||
|
||||
$addMethodCall = false; // Whether the method should be added to the definition as a call or as arguments
|
||||
foreach ($reflectionMethod->getParameters() as $index => $parameter) {
|
||||
if (array_key_exists($index, $arguments) && '' !== $arguments[$index]) {
|
||||
continue;
|
||||
}
|
||||
@ -111,9 +180,13 @@ class AutowirePass implements CompilerPassInterface
|
||||
if (!$typeHint = $parameter->getClass()) {
|
||||
// no default value? Then fail
|
||||
if (!$parameter->isOptional()) {
|
||||
if ($isConstructor) {
|
||||
throw new RuntimeException(sprintf('Unable to autowire argument index %d ($%s) for the service "%s". If this is an object, give it a type-hint. Otherwise, specify this argument\'s value explicitly.', $index, $parameter->name, $id));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// specifically pass the default value
|
||||
$arguments[$index] = $parameter->getDefaultValue();
|
||||
|
||||
@ -126,26 +199,37 @@ class AutowirePass implements CompilerPassInterface
|
||||
|
||||
if (isset($this->types[$typeHint->name])) {
|
||||
$value = new Reference($this->types[$typeHint->name]);
|
||||
$addMethodCall = true;
|
||||
} else {
|
||||
try {
|
||||
$value = $this->createAutowiredDefinition($typeHint, $id);
|
||||
$addMethodCall = true;
|
||||
} catch (RuntimeException $e) {
|
||||
if ($parameter->allowsNull()) {
|
||||
$value = null;
|
||||
} elseif ($parameter->isDefaultValueAvailable()) {
|
||||
$value = $parameter->getDefaultValue();
|
||||
} else {
|
||||
// The exception code is set to 1 if the exception must be thrown even if it's a setter
|
||||
if (1 === $e->getCode() || $isConstructor) {
|
||||
throw $e;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (\ReflectionException $e) {
|
||||
// Typehint against a non-existing class
|
||||
|
||||
if (!$parameter->isDefaultValueAvailable()) {
|
||||
if ($isConstructor) {
|
||||
throw new RuntimeException(sprintf('Cannot autowire argument %s for %s because the type-hinted class does not exist (%s).', $index + 1, $definition->getClass(), $e->getMessage()), 0, $e);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$value = $parameter->getDefaultValue();
|
||||
}
|
||||
|
||||
@ -155,7 +239,12 @@ class AutowirePass implements CompilerPassInterface
|
||||
// it's possible index 1 was set, then index 0, then 2, etc
|
||||
// make sure that we re-order so they're injected as expected
|
||||
ksort($arguments);
|
||||
|
||||
if ($isConstructor) {
|
||||
$definition->setArguments($arguments);
|
||||
} elseif ($addMethodCall) {
|
||||
$definition->addMethodCall($reflectionMethod->name, $arguments);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -253,7 +342,7 @@ class AutowirePass implements CompilerPassInterface
|
||||
$classOrInterface = $typeHint->isInterface() ? 'interface' : 'class';
|
||||
$matchingServices = implode(', ', $this->ambiguousServiceTypes[$typeHint->name]);
|
||||
|
||||
throw new RuntimeException(sprintf('Unable to autowire argument of type "%s" for the service "%s". Multiple services exist for this %s (%s).', $typeHint->name, $id, $classOrInterface, $matchingServices));
|
||||
throw new RuntimeException(sprintf('Unable to autowire argument of type "%s" for the service "%s". Multiple services exist for this %s (%s).', $typeHint->name, $id, $classOrInterface, $matchingServices), 1);
|
||||
}
|
||||
|
||||
if (!$typeHint->isInstantiable()) {
|
||||
@ -269,7 +358,7 @@ class AutowirePass implements CompilerPassInterface
|
||||
$this->populateAvailableType($argumentId, $argumentDefinition);
|
||||
|
||||
try {
|
||||
$this->completeDefinition($argumentId, $argumentDefinition);
|
||||
$this->completeDefinition($argumentId, $argumentDefinition, array('__construct'));
|
||||
} catch (RuntimeException $e) {
|
||||
$classOrInterface = $typeHint->isInterface() ? 'interface' : 'class';
|
||||
$message = sprintf('Unable to autowire argument of type "%s" for the service "%s". No services were found matching this %s and it cannot be auto-registered.', $typeHint->name, $id, $classOrInterface);
|
||||
@ -320,20 +409,6 @@ class AutowirePass implements CompilerPassInterface
|
||||
$this->ambiguousServiceTypes[$type][] = $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \ReflectionClass $reflectionClass
|
||||
*
|
||||
* @return \ReflectionMethod[]
|
||||
*/
|
||||
private static function getSetters(\ReflectionClass $reflectionClass)
|
||||
{
|
||||
foreach ($reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $reflectionMethod) {
|
||||
if (!$reflectionMethod->isStatic() && 1 === $reflectionMethod->getNumberOfParameters() && 0 === strpos($reflectionMethod->name, 'set')) {
|
||||
yield $reflectionMethod;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static function getResourceMetadataForMethod(\ReflectionMethod $method)
|
||||
{
|
||||
$methodArgumentsMetadata = array();
|
||||
|
@ -38,6 +38,11 @@ class LoggingFormatter
|
||||
return $this->format($pass, sprintf('Resolving inheritance for "%s" (parent: %s).', $childId, $parentId));
|
||||
}
|
||||
|
||||
public function formatUnusedAutowiringPatterns(CompilerPassInterface $pass, $id, array $patterns)
|
||||
{
|
||||
return $this->format($pass, sprintf('Autowiring\'s patterns "%s" for service "%s" don\'t match any method.', implode('", "', $patterns), $id));
|
||||
}
|
||||
|
||||
public function format(CompilerPassInterface $pass, $message)
|
||||
{
|
||||
return sprintf('%s: %s', get_class($pass), $message);
|
||||
|
@ -36,7 +36,7 @@ class Definition
|
||||
private $abstract = false;
|
||||
private $lazy = false;
|
||||
private $decoratedService;
|
||||
private $autowired = false;
|
||||
private $autowiredMethods = array();
|
||||
private $autowiringTypes = array();
|
||||
|
||||
protected $arguments;
|
||||
@ -662,19 +662,50 @@ class Definition
|
||||
*/
|
||||
public function isAutowired()
|
||||
{
|
||||
return $this->autowired;
|
||||
return !empty($this->autowiredMethods);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets autowired methods.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function getAutowiredMethods()
|
||||
{
|
||||
return $this->autowiredMethods;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets autowired.
|
||||
*
|
||||
* Allowed values:
|
||||
* - true: constructor autowiring, same as $this->setAutowiredMethods(array('__construct'))
|
||||
* - false: no autowiring, same as $this->setAutowiredMethods(array())
|
||||
*
|
||||
* @param bool $autowired
|
||||
*
|
||||
* @return Definition The current instance
|
||||
*/
|
||||
public function setAutowired($autowired)
|
||||
{
|
||||
$this->autowired = $autowired;
|
||||
$this->autowiredMethods = $autowired ? array('__construct') : array();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets autowired methods.
|
||||
*
|
||||
* Example of allowed value:
|
||||
* - array('__construct', 'set*', 'initialize'): autowire whitelisted methods only
|
||||
*
|
||||
* @param string[] $autowiredMethods
|
||||
*
|
||||
* @return Definition The current instance
|
||||
*/
|
||||
public function setAutowiredMethods(array $autowiredMethods)
|
||||
{
|
||||
$this->autowiredMethods = $autowiredMethods;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
@ -239,6 +239,19 @@ class XmlFileLoader extends FileLoader
|
||||
$definition->addAutowiringType($type->textContent);
|
||||
}
|
||||
|
||||
$autowireTags = array();
|
||||
foreach ($this->getChildren($service, 'autowire') as $type) {
|
||||
$autowireTags[] = $type->textContent;
|
||||
}
|
||||
|
||||
if ($autowireTags) {
|
||||
if ($service->hasAttribute('autowire')) {
|
||||
throw new InvalidArgumentException(sprintf('The "autowire" attribute cannot be used together with "<autowire>" tags for service "%s" in %s.', (string) $service->getAttribute('id'), $file));
|
||||
}
|
||||
|
||||
$definition->setAutowiredMethods($autowireTags);
|
||||
}
|
||||
|
||||
if ($value = $service->getAttribute('decorates')) {
|
||||
$renameId = $service->hasAttribute('decoration-inner-name') ? $service->getAttribute('decoration-inner-name') : null;
|
||||
$priority = $service->hasAttribute('decoration-priority') ? $service->getAttribute('decoration-priority') : 0;
|
||||
|
@ -302,8 +302,12 @@ class YamlFileLoader extends FileLoader
|
||||
}
|
||||
|
||||
if (isset($service['autowire'])) {
|
||||
if (is_array($service['autowire'])) {
|
||||
$definition->setAutowiredMethods($service['autowire']);
|
||||
} else {
|
||||
$definition->setAutowired($service['autowire']);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($service['autowiring_types'])) {
|
||||
if (is_string($service['autowiring_types'])) {
|
||||
|
@ -100,6 +100,7 @@
|
||||
<xsd:element name="tag" type="tag" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xsd:element name="property" type="property" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xsd:element name="autowiring-type" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xsd:element name="autowire" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
|
||||
</xsd:choice>
|
||||
<xsd:attribute name="id" type="xsd:string" />
|
||||
<xsd:attribute name="class" type="xsd:string" />
|
||||
|
@ -429,6 +429,74 @@ class AutowirePassTest extends \PHPUnit_Framework_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);
|
||||
|
||||
// manually configure *one* call, to override autowiring
|
||||
$container
|
||||
->register('setter_injection', SetterInjection::class)
|
||||
->setAutowiredMethods(array('__construct', 'set*'))
|
||||
->addMethodCall('setWithCallsConfigured', array('manual_arg1', 'manual_arg2'))
|
||||
;
|
||||
|
||||
$pass = new AutowirePass();
|
||||
$pass->process($container);
|
||||
|
||||
$methodCalls = $container->getDefinition('setter_injection')->getMethodCalls();
|
||||
|
||||
// grab the call method names
|
||||
$actualMethodNameCalls = array_map(function ($call) {
|
||||
return $call[0];
|
||||
}, $methodCalls);
|
||||
$this->assertEquals(
|
||||
array('setWithCallsConfigured', 'setFoo', 'setDependencies'),
|
||||
$actualMethodNameCalls
|
||||
);
|
||||
|
||||
// test setWithCallsConfigured args
|
||||
$this->assertEquals(
|
||||
array('manual_arg1', 'manual_arg2'),
|
||||
$methodCalls[0][1]
|
||||
);
|
||||
// test setFoo args
|
||||
$this->assertEquals(
|
||||
array(new Reference('app_foo')),
|
||||
$methodCalls[1][1]
|
||||
);
|
||||
}
|
||||
|
||||
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('setter_injection', SetterInjection::class)
|
||||
->setAutowiredMethods(array('setFoo', 'notASetter'))
|
||||
;
|
||||
|
||||
$pass = new AutowirePass();
|
||||
$pass->process($container);
|
||||
|
||||
$methodCalls = $container->getDefinition('setter_injection')->getMethodCalls();
|
||||
|
||||
$actualMethodNameCalls = array_map(function ($call) {
|
||||
return $call[0];
|
||||
}, $methodCalls);
|
||||
$this->assertEquals(
|
||||
array('setFoo', 'notASetter'),
|
||||
$actualMethodNameCalls
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getCreateResourceTests
|
||||
*/
|
||||
@ -476,6 +544,37 @@ class AutowirePassTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
$this->assertTrue($container->hasDefinition('bar'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
|
||||
* @expectedExceptionMessage Unable to autowire argument of type "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" for the service "setter_injection_collision". Multiple services exist for this interface (c1, c2).
|
||||
* @expectedExceptionCode 1
|
||||
*/
|
||||
public function testSetterInjectionCollisionThrowsException()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$container->register('c1', CollisionA::class);
|
||||
$container->register('c2', CollisionB::class);
|
||||
$aDefinition = $container->register('setter_injection_collision', SetterInjectionCollision::class);
|
||||
$aDefinition->setAutowiredMethods(array('__construct', 'set*'));
|
||||
|
||||
$pass = new AutowirePass();
|
||||
$pass->process($container);
|
||||
}
|
||||
|
||||
public function testLogUnusedPatterns()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$definition = $container->register('foo', Foo::class);
|
||||
$definition->setAutowiredMethods(array('not', 'exist*'));
|
||||
|
||||
$pass = new AutowirePass();
|
||||
$pass->process($container);
|
||||
|
||||
$this->assertEquals(array(AutowirePass::class.': Autowiring\'s patterns "not", "exist*" for service "foo" don\'t match any method.'), $container->getCompiler()->getLog());
|
||||
}
|
||||
}
|
||||
|
||||
class Foo
|
||||
@ -648,9 +747,74 @@ class ClassForResource
|
||||
class IdenticalClassResource extends ClassForResource
|
||||
{
|
||||
}
|
||||
|
||||
class ClassChangedConstructorArgs extends ClassForResource
|
||||
{
|
||||
public function __construct($foo, Bar $bar, $baz)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
class SetterInjection
|
||||
{
|
||||
public function setFoo(Foo $foo)
|
||||
{
|
||||
// should be called
|
||||
}
|
||||
|
||||
public function setDependencies(Foo $foo, A $a)
|
||||
{
|
||||
// should be called
|
||||
}
|
||||
|
||||
public function setBar()
|
||||
{
|
||||
// should not be called
|
||||
}
|
||||
|
||||
public function setNotAutowireable(NotARealClass $n)
|
||||
{
|
||||
// should not be called
|
||||
}
|
||||
|
||||
public function setArgCannotAutowire($foo)
|
||||
{
|
||||
// should not be called
|
||||
}
|
||||
|
||||
public function setOptionalNotAutowireable(NotARealClass $n = null)
|
||||
{
|
||||
// should not be called
|
||||
}
|
||||
|
||||
public function setOptionalNoTypeHint($foo = null)
|
||||
{
|
||||
// should not be called
|
||||
}
|
||||
|
||||
public function setOptionalArgNoAutowireable($other = 'default_val')
|
||||
{
|
||||
// should not be called
|
||||
}
|
||||
|
||||
public function setWithCallsConfigured(A $a)
|
||||
{
|
||||
// this method has a calls configured on it
|
||||
// should not be called
|
||||
}
|
||||
|
||||
public function notASetter(A $a)
|
||||
{
|
||||
// should be called only when explicitly specified
|
||||
}
|
||||
}
|
||||
|
||||
class SetterInjectionCollision
|
||||
{
|
||||
public function setMultipleInstancesForOneArg(CollisionInterface $collision)
|
||||
{
|
||||
// The CollisionInterface cannot be autowired - there are multiple
|
||||
|
||||
// should throw an exception
|
||||
}
|
||||
}
|
||||
|
@ -290,6 +290,16 @@ class DefinitionTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertFalse($def->isAutowired());
|
||||
$def->setAutowired(true);
|
||||
$this->assertTrue($def->isAutowired());
|
||||
$this->assertEquals(array('__construct'), $def->getAutowiredMethods());
|
||||
|
||||
$def->setAutowiredMethods(array('foo'));
|
||||
$def->setAutowired(false);
|
||||
$this->assertSame(array(), $def->getAutowiredMethods());
|
||||
$this->assertFalse($def->isAutowired());
|
||||
|
||||
$def->setAutowiredMethods(array('getFoo', 'getBar'));
|
||||
$this->assertEquals(array('getFoo', 'getBar'), $def->getAutowiredMethods());
|
||||
$this->assertTrue($def->isAutowired());
|
||||
}
|
||||
|
||||
public function testTypes()
|
||||
|
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<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="autowire_array" class="Foo">
|
||||
<autowire>set*</autowire>
|
||||
<autowire>bar</autowire>
|
||||
</service>
|
||||
</services>
|
||||
</container>
|
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<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="autowire_array" class="Foo" autowire="*">
|
||||
<autowire>setFoo</autowire>
|
||||
</service>
|
||||
</services>
|
||||
</container>
|
@ -0,0 +1,4 @@
|
||||
services:
|
||||
autowire_array:
|
||||
class: Foo
|
||||
autowire: ['set*', 'bar']
|
@ -554,6 +554,20 @@ class XmlFileLoaderTest extends \PHPUnit_Framework_TestCase
|
||||
$loader->load('services23.xml');
|
||||
|
||||
$this->assertTrue($container->getDefinition('bar')->isAutowired());
|
||||
$this->assertEquals(array('__construct'), $container->getDefinition('bar')->getAutowiredMethods());
|
||||
|
||||
$loader->load('services27.xml');
|
||||
$this->assertEquals(array('set*', 'bar'), $container->getDefinition('autowire_array')->getAutowiredMethods());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException
|
||||
*/
|
||||
public function testAutowireAttributeAndTag()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml'));
|
||||
$loader->load('services28.xml');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -323,6 +323,10 @@ class YamlFileLoaderTest extends \PHPUnit_Framework_TestCase
|
||||
$loader->load('services23.yml');
|
||||
|
||||
$this->assertTrue($container->getDefinition('bar_service')->isAutowired());
|
||||
$this->assertEquals(array('__construct'), $container->getDefinition('bar_service')->getAutowiredMethods());
|
||||
|
||||
$loader->load('services27.yml');
|
||||
$this->assertEquals(array('set*', 'bar'), $container->getDefinition('autowire_array')->getAutowiredMethods());
|
||||
}
|
||||
|
||||
/**
|
||||
|
Reference in New Issue
Block a user