[DependencyInjection] Add autowiring capabilities
This commit is contained in:
parent
bee1faaa95
commit
aee57315c5
@ -0,0 +1,263 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
* Guesses constructor arguments of services definitions and try to instantiate services if necessary.
|
||||
*
|
||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||
*/
|
||||
class AutowirePass implements CompilerPassInterface
|
||||
{
|
||||
private $container;
|
||||
private $reflectionClasses = array();
|
||||
private $definedTypes = array();
|
||||
private $types;
|
||||
private $notGuessableTypes = array();
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
foreach ($container->getDefinitions() as $id => $definition) {
|
||||
if ($definition->isAutowired()) {
|
||||
$this->completeDefinition($id, $definition);
|
||||
}
|
||||
}
|
||||
|
||||
// Free memory and remove circular reference to container
|
||||
$this->container = null;
|
||||
$this->reflectionClasses = array();
|
||||
$this->definedTypes = array();
|
||||
$this->types = null;
|
||||
$this->notGuessableTypes = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Wires the given definition.
|
||||
*
|
||||
* @param string $id
|
||||
* @param Definition $definition
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
private function completeDefinition($id, Definition $definition)
|
||||
{
|
||||
if (!$reflectionClass = $this->getReflectionClass($id, $definition)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->container->addClassResource($reflectionClass);
|
||||
|
||||
if (!$constructor = $reflectionClass->getConstructor()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$arguments = $definition->getArguments();
|
||||
foreach ($constructor->getParameters() as $index => $parameter) {
|
||||
$argumentExists = array_key_exists($index, $arguments);
|
||||
if ($argumentExists && '' !== $arguments[$index]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!$typeHint = $parameter->getClass()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (null === $this->types) {
|
||||
$this->populateAvailableTypes();
|
||||
}
|
||||
|
||||
if (isset($this->types[$typeHint->name])) {
|
||||
$value = new Reference($this->types[$typeHint->name]);
|
||||
} else {
|
||||
try {
|
||||
$value = $this->createAutowiredDefinition($typeHint, $id);
|
||||
} catch (RuntimeException $e) {
|
||||
if (!$parameter->isDefaultValueAvailable()) {
|
||||
throw $e;
|
||||
}
|
||||
|
||||
$value = $parameter->getDefaultValue();
|
||||
}
|
||||
}
|
||||
} catch (\ReflectionException $reflectionException) {
|
||||
// Typehint against a non-existing class
|
||||
|
||||
if (!$parameter->isDefaultValueAvailable()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$value = $parameter->getDefaultValue();
|
||||
}
|
||||
|
||||
if ($argumentExists) {
|
||||
$definition->replaceArgument($index, $value);
|
||||
} else {
|
||||
$definition->addArgument($value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the list of available types.
|
||||
*/
|
||||
private function populateAvailableTypes()
|
||||
{
|
||||
$this->types = array();
|
||||
|
||||
foreach ($this->container->getDefinitions() as $id => $definition) {
|
||||
$this->populateAvailableType($id, $definition);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the list of available types for a given definition.
|
||||
*
|
||||
* @param string $id
|
||||
* @param Definition $definition
|
||||
*/
|
||||
private function populateAvailableType($id, Definition $definition)
|
||||
{
|
||||
if (!$definition->getClass()) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($definition->getAutowiringTypes() as $type) {
|
||||
$this->definedTypes[$type] = true;
|
||||
$this->types[$type] = $id;
|
||||
}
|
||||
|
||||
if ($reflectionClass = $this->getReflectionClass($id, $definition)) {
|
||||
$this->extractInterfaces($id, $reflectionClass);
|
||||
$this->extractAncestors($id, $reflectionClass);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the list of all interfaces implemented by a class.
|
||||
*
|
||||
* @param string $id
|
||||
* @param \ReflectionClass $reflectionClass
|
||||
*/
|
||||
private function extractInterfaces($id, \ReflectionClass $reflectionClass)
|
||||
{
|
||||
foreach ($reflectionClass->getInterfaces() as $interfaceName => $reflectionInterface) {
|
||||
$this->set($interfaceName, $id);
|
||||
|
||||
$this->extractInterfaces($id, $reflectionInterface);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts all inherited types of a class.
|
||||
*
|
||||
* @param string $id
|
||||
* @param \ReflectionClass $reflectionClass
|
||||
*/
|
||||
private function extractAncestors($id, \ReflectionClass $reflectionClass)
|
||||
{
|
||||
$this->set($reflectionClass->name, $id);
|
||||
|
||||
if ($reflectionParentClass = $reflectionClass->getParentClass()) {
|
||||
$this->extractAncestors($id, $reflectionParentClass);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Associates a type and a service id if applicable.
|
||||
*
|
||||
* @param string $type
|
||||
* @param string $id
|
||||
*/
|
||||
private function set($type, $id)
|
||||
{
|
||||
if (isset($this->definedTypes[$type]) || isset($this->notGuessableTypes[$type])) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($this->types[$type])) {
|
||||
if ($this->types[$type] === $id) {
|
||||
return;
|
||||
}
|
||||
|
||||
unset($this->types[$type]);
|
||||
$this->notGuessableTypes[$type] = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->types[$type] = $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a definition for the type if possible or throws an exception.
|
||||
*
|
||||
* @param \ReflectionClass $typeHint
|
||||
* @param string $id
|
||||
*
|
||||
* @return Reference A reference to the registered definition
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
private function createAutowiredDefinition(\ReflectionClass $typeHint, $id)
|
||||
{
|
||||
if (!$typeHint->isInstantiable()) {
|
||||
throw new RuntimeException(sprintf('Unable to autowire argument of type "%s" for the service "%s".', $typeHint->name, $id));
|
||||
}
|
||||
|
||||
$argumentId = sprintf('autowired.%s', $typeHint->name);
|
||||
|
||||
$argumentDefinition = $this->container->register($argumentId, $typeHint->name);
|
||||
$argumentDefinition->setPublic(false);
|
||||
|
||||
$this->populateAvailableType($argumentId, $argumentDefinition);
|
||||
$this->completeDefinition($argumentId, $argumentDefinition);
|
||||
|
||||
return new Reference($argumentId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the reflection class associated with the given service.
|
||||
*
|
||||
* @param string $id
|
||||
* @param Definition $definition
|
||||
*
|
||||
* @return \ReflectionClass|null
|
||||
*/
|
||||
private function getReflectionClass($id, Definition $definition)
|
||||
{
|
||||
if (isset($this->reflectionClasses[$id])) {
|
||||
return $this->reflectionClasses[$id];
|
||||
}
|
||||
|
||||
if (!$class = $definition->getClass()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$class = $this->container->getParameterBag()->resolveValue($class);
|
||||
|
||||
try {
|
||||
return $this->reflectionClasses[$id] = new \ReflectionClass($class);
|
||||
} catch (\ReflectionException $reflectionException) {
|
||||
// return null
|
||||
}
|
||||
}
|
||||
}
|
@ -50,6 +50,7 @@ class PassConfig
|
||||
new CheckDefinitionValidityPass(),
|
||||
new ResolveReferencesToAliasesPass(),
|
||||
new ResolveInvalidReferencesPass(),
|
||||
new AutowirePass(),
|
||||
new AnalyzeServiceReferencesPass(true),
|
||||
new CheckCircularReferencesPass(),
|
||||
new CheckReferenceValidityPass(),
|
||||
|
@ -41,6 +41,8 @@ class Definition
|
||||
private $synchronized = false;
|
||||
private $lazy = false;
|
||||
private $decoratedService;
|
||||
private $autowired = false;
|
||||
private $autowiringTypes = array();
|
||||
|
||||
protected $arguments;
|
||||
|
||||
@ -818,4 +820,96 @@ class Definition
|
||||
{
|
||||
return $this->configurator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets types that will default to this definition.
|
||||
*
|
||||
* @param string[] $types
|
||||
*
|
||||
* @return Definition The current instance
|
||||
*/
|
||||
public function setAutowiringTypes(array $types)
|
||||
{
|
||||
$this->autowiringTypes = array();
|
||||
|
||||
foreach ($types as $type) {
|
||||
$this->autowiringTypes[$type] = true;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the definition autowired?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isAutowired()
|
||||
{
|
||||
return $this->autowired;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets autowired.
|
||||
*
|
||||
* @param $autowired
|
||||
*
|
||||
* @return Definition The current instance
|
||||
*/
|
||||
public function setAutowired($autowired)
|
||||
{
|
||||
$this->autowired = $autowired;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets autowiring types that will default to this definition.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function getAutowiringTypes()
|
||||
{
|
||||
return array_keys($this->autowiringTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a type that will default to this definition.
|
||||
*
|
||||
* @param string $type
|
||||
*
|
||||
* @return Definition The current instance
|
||||
*/
|
||||
public function addAutowiringType($type)
|
||||
{
|
||||
$this->autowiringTypes[$type] = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a type.
|
||||
*
|
||||
* @param string $type
|
||||
*
|
||||
* @return Definition The current instance
|
||||
*/
|
||||
public function removeAutowiringType($type)
|
||||
{
|
||||
unset($this->autowiringTypes[$type]);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will this definition default for the given type?
|
||||
*
|
||||
* @param string $type
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasAutowiringType($type)
|
||||
{
|
||||
return isset($this->autowiringTypes[$type]);
|
||||
}
|
||||
}
|
||||
|
@ -157,6 +157,10 @@ class XmlFileLoader extends FileLoader
|
||||
}
|
||||
}
|
||||
|
||||
if ($value = $service->getAttribute('autowire')) {
|
||||
$definition->setAutowired(XmlUtils::phpize($value));
|
||||
}
|
||||
|
||||
if ($value = $service->getAttribute('scope')) {
|
||||
$triggerDeprecation = 'request' !== (string) $service->getAttribute('id');
|
||||
|
||||
@ -247,6 +251,10 @@ class XmlFileLoader extends FileLoader
|
||||
$definition->addTag($tag->getAttribute('name'), $parameters);
|
||||
}
|
||||
|
||||
foreach ($this->getChildren($service, 'autowiring-type') as $type) {
|
||||
$definition->addAutowiringType($type->textContent);
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -299,6 +299,28 @@ class YamlFileLoader extends FileLoader
|
||||
$definition->setDecoratedService($service['decorates'], $renameId, $priority);
|
||||
}
|
||||
|
||||
if (isset($service['autowire'])) {
|
||||
$definition->setAutowired($service['autowire']);
|
||||
}
|
||||
|
||||
if (isset($service['autowiring_types'])) {
|
||||
if (is_string($service['autowiring_types'])) {
|
||||
$definition->addAutowiringType($service['autowiring_types']);
|
||||
} else {
|
||||
if (!is_array($service['autowiring_types'])) {
|
||||
throw new InvalidArgumentException(sprintf('Parameter "autowiring_types" must be a string or an array for service "%s" in %s. Check your YAML syntax.', $id, $file));
|
||||
}
|
||||
|
||||
foreach ($service['autowiring_types'] as $autowiringType) {
|
||||
if (!is_string($autowiringType)) {
|
||||
throw new InvalidArgumentException(sprintf('A "autowiring_types" attribute must be of type string for service "%s" in %s. Check your YAML syntax.', $id, $file));
|
||||
}
|
||||
|
||||
$definition->addAutowiringType($autowiringType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->container->setDefinition($id, $definition);
|
||||
}
|
||||
|
||||
|
@ -85,6 +85,7 @@
|
||||
<xsd:element name="call" type="call" minOccurs="0" maxOccurs="unbounded" />
|
||||
<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:choice>
|
||||
<xsd:attribute name="id" type="xsd:string" />
|
||||
<xsd:attribute name="class" type="xsd:string" />
|
||||
@ -103,6 +104,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="boolean" />
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="tag">
|
||||
|
@ -0,0 +1,300 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Tests\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Compiler\AutowirePass;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||
*/
|
||||
class AutowirePassTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testProcess()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$container->register('foo', __NAMESPACE__.'\Foo');
|
||||
$barDefinition = $container->register('bar', __NAMESPACE__.'\Bar');
|
||||
$barDefinition->setAutowired(true);
|
||||
|
||||
$pass = new AutowirePass();
|
||||
$pass->process($container);
|
||||
|
||||
$this->assertCount(1, $container->getDefinition('bar')->getArguments());
|
||||
$this->assertEquals('foo', (string) $container->getDefinition('bar')->getArgument(0));
|
||||
}
|
||||
|
||||
public function testProcessAutowireParent()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$container->register('b', __NAMESPACE__.'\B');
|
||||
$cDefinition = $container->register('c', __NAMESPACE__.'\C');
|
||||
$cDefinition->setAutowired(true);
|
||||
|
||||
$pass = new AutowirePass();
|
||||
$pass->process($container);
|
||||
|
||||
$this->assertCount(1, $container->getDefinition('c')->getArguments());
|
||||
$this->assertEquals('b', (string) $container->getDefinition('c')->getArgument(0));
|
||||
}
|
||||
|
||||
public function testProcessAutowireInterface()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$container->register('f', __NAMESPACE__.'\F');
|
||||
$gDefinition = $container->register('g', __NAMESPACE__.'\G');
|
||||
$gDefinition->setAutowired(true);
|
||||
|
||||
$pass = new AutowirePass();
|
||||
$pass->process($container);
|
||||
|
||||
$this->assertCount(2, $container->getDefinition('g')->getArguments());
|
||||
$this->assertEquals('f', (string) $container->getDefinition('g')->getArgument(0));
|
||||
$this->assertEquals('f', (string) $container->getDefinition('g')->getArgument(1));
|
||||
}
|
||||
|
||||
public function testCompleteExistingDefinition()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$container->register('b', __NAMESPACE__.'\B');
|
||||
$container->register('f', __NAMESPACE__.'\F');
|
||||
$hDefinition = $container->register('h', __NAMESPACE__.'\H')->addArgument(new Reference('b'));
|
||||
$hDefinition->setAutowired(true);
|
||||
|
||||
$pass = new AutowirePass();
|
||||
$pass->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));
|
||||
}
|
||||
|
||||
public function testCompleteExistingDefinitionWithNotDefinedArguments()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$container->register('b', __NAMESPACE__.'\B');
|
||||
$container->register('f', __NAMESPACE__.'\F');
|
||||
$hDefinition = $container->register('h', __NAMESPACE__.'\H')->addArgument('')->addArgument('');
|
||||
$hDefinition->setAutowired(true);
|
||||
|
||||
$pass = new AutowirePass();
|
||||
$pass->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));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
|
||||
* @expectedExceptionMessage Unable to autowire argument of type "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" for the service "a".
|
||||
*/
|
||||
public function testTypeCollision()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$container->register('c1', __NAMESPACE__.'\CollisionA');
|
||||
$container->register('c2', __NAMESPACE__.'\CollisionB');
|
||||
$aDefinition = $container->register('a', __NAMESPACE__.'\CannotBeAutowired');
|
||||
$aDefinition->setAutowired(true);
|
||||
|
||||
$pass = new AutowirePass();
|
||||
$pass->process($container);
|
||||
}
|
||||
|
||||
public function testWithTypeSet()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$container->register('c1', __NAMESPACE__.'\CollisionA');
|
||||
$container->register('c2', __NAMESPACE__.'\CollisionB')->addAutowiringType(__NAMESPACE__.'\CollisionInterface');
|
||||
$aDefinition = $container->register('a', __NAMESPACE__.'\CannotBeAutowired');
|
||||
$aDefinition->setAutowired(true);
|
||||
|
||||
$pass = new AutowirePass();
|
||||
$pass->process($container);
|
||||
|
||||
$this->assertCount(1, $container->getDefinition('a')->getArguments());
|
||||
$this->assertEquals('c2', (string) $container->getDefinition('a')->getArgument(0));
|
||||
}
|
||||
|
||||
public function testCreateDefinition()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$coopTilleulsDefinition = $container->register('coop_tilleuls', __NAMESPACE__.'\LesTilleuls');
|
||||
$coopTilleulsDefinition->setAutowired(true);
|
||||
|
||||
$pass = new AutowirePass();
|
||||
$pass->process($container);
|
||||
|
||||
$this->assertCount(1, $container->getDefinition('coop_tilleuls')->getArguments());
|
||||
$this->assertEquals('autowired.symfony\component\dependencyinjection\tests\compiler\dunglas', $container->getDefinition('coop_tilleuls')->getArgument(0));
|
||||
|
||||
$dunglasDefinition = $container->getDefinition('autowired.symfony\component\dependencyinjection\tests\compiler\dunglas');
|
||||
$this->assertEquals(__NAMESPACE__.'\Dunglas', $dunglasDefinition->getClass());
|
||||
$this->assertFalse($dunglasDefinition->isPublic());
|
||||
$this->assertCount(1, $dunglasDefinition->getArguments());
|
||||
$this->assertEquals('autowired.symfony\component\dependencyinjection\tests\compiler\lille', $dunglasDefinition->getArgument(0));
|
||||
|
||||
$lilleDefinition = $container->getDefinition('autowired.symfony\component\dependencyinjection\tests\compiler\lille');
|
||||
$this->assertEquals(__NAMESPACE__.'\Lille', $lilleDefinition->getClass());
|
||||
}
|
||||
|
||||
public function testResolveParameter()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$container->setParameter('class_name', __NAMESPACE__.'\Foo');
|
||||
$container->register('foo', '%class_name%');
|
||||
$barDefinition = $container->register('bar', __NAMESPACE__.'\Bar');
|
||||
$barDefinition->setAutowired(true);
|
||||
|
||||
$pass = new AutowirePass();
|
||||
$pass->process($container);
|
||||
|
||||
$this->assertEquals('foo', $container->getDefinition('bar')->getArgument(0));
|
||||
}
|
||||
|
||||
public function testOptionalParameter()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$container->register('a', __NAMESPACE__.'\A');
|
||||
$container->register('foo', __NAMESPACE__.'\Foo');
|
||||
$optDefinition = $container->register('opt', __NAMESPACE__.'\OptionalParameter');
|
||||
$optDefinition->setAutowired(true);
|
||||
|
||||
$pass = new AutowirePass();
|
||||
$pass->process($container);
|
||||
|
||||
$definition = $container->getDefinition('opt');
|
||||
$this->assertNull($definition->getArgument(0));
|
||||
$this->assertEquals('a', $definition->getArgument(1));
|
||||
$this->assertEquals('foo', $definition->getArgument(2));
|
||||
}
|
||||
|
||||
public function testDontTriggeruAutowiring()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$container->register('foo', __NAMESPACE__.'\Foo');
|
||||
$container->register('bar', __NAMESPACE__.'\Bar');
|
||||
|
||||
$pass = new AutowirePass();
|
||||
$pass->process($container);
|
||||
|
||||
$this->assertCount(0, $container->getDefinition('bar')->getArguments());
|
||||
}
|
||||
}
|
||||
|
||||
class Foo
|
||||
{
|
||||
}
|
||||
|
||||
class Bar
|
||||
{
|
||||
public function __construct(Foo $foo)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
class A
|
||||
{
|
||||
}
|
||||
|
||||
class B extends A
|
||||
{
|
||||
}
|
||||
|
||||
class C
|
||||
{
|
||||
public function __construct(A $a)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
interface DInterface
|
||||
{
|
||||
}
|
||||
|
||||
interface EInterface extends DInterface
|
||||
{
|
||||
}
|
||||
|
||||
class F implements EInterface
|
||||
{
|
||||
}
|
||||
|
||||
class G
|
||||
{
|
||||
public function __construct(DInterface $d, EInterface $e)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
class H
|
||||
{
|
||||
public function __construct(B $b, DInterface $d)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
interface CollisionInterface
|
||||
{
|
||||
}
|
||||
|
||||
class CollisionA implements CollisionInterface
|
||||
{
|
||||
}
|
||||
|
||||
class CollisionB implements CollisionInterface
|
||||
{
|
||||
}
|
||||
|
||||
class CannotBeAutowired
|
||||
{
|
||||
public function __construct(CollisionInterface $collision)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
class Lille
|
||||
{
|
||||
}
|
||||
|
||||
class Dunglas
|
||||
{
|
||||
public function __construct(Lille $l)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
class LesTilleuls
|
||||
{
|
||||
public function __construct(Dunglas $k)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
class OptionalParameter
|
||||
{
|
||||
public function __construct(CollisionInterface $c = null, A $a, Foo $f = null)
|
||||
{
|
||||
}
|
||||
}
|
@ -890,6 +890,19 @@ class ContainerBuilderTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
$this->assertTrue($classInList);
|
||||
}
|
||||
|
||||
public function testAutowiring()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$container->register('a', __NAMESPACE__.'\A');
|
||||
$bDefinition = $container->register('b', __NAMESPACE__.'\B');
|
||||
$bDefinition->setAutowired(true);
|
||||
|
||||
$container->compile();
|
||||
|
||||
$this->assertEquals('a', (string) $container->getDefinition('b')->getArgument(0));
|
||||
}
|
||||
}
|
||||
|
||||
class FooClass
|
||||
@ -903,3 +916,14 @@ class ProjectContainer extends ContainerBuilder
|
||||
throw new InactiveScopeException('foo', 'request');
|
||||
}
|
||||
}
|
||||
|
||||
class A
|
||||
{
|
||||
}
|
||||
|
||||
class B
|
||||
{
|
||||
public function __construct(A $a)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
@ -394,4 +394,25 @@ class DefinitionTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertSame($def, $def->setProperty('foo', 'bar'));
|
||||
$this->assertEquals(array('foo' => 'bar'), $def->getProperties());
|
||||
}
|
||||
|
||||
public function testAutowired()
|
||||
{
|
||||
$def = new Definition('stdClass');
|
||||
$this->assertFalse($def->isAutowired());
|
||||
$def->setAutowired(true);
|
||||
$this->assertTrue($def->isAutowired());
|
||||
}
|
||||
|
||||
public function testTypes()
|
||||
{
|
||||
$def = new Definition('stdClass');
|
||||
|
||||
$this->assertEquals(array(), $def->getAutowiringTypes());
|
||||
$this->assertSame($def, $def->setAutowiringTypes(array('Foo')));
|
||||
$this->assertEquals(array('Foo'), $def->getAutowiringTypes());
|
||||
$this->assertSame($def, $def->addAutowiringType('Bar'));
|
||||
$this->assertTrue($def->hasAutowiringType('Bar'));
|
||||
$this->assertSame($def, $def->removeAutowiringType('Foo'));
|
||||
$this->assertEquals(array('Bar'), $def->getAutowiringTypes());
|
||||
}
|
||||
}
|
||||
|
@ -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="foo" class="Foo">
|
||||
<autowiring-type>Bar</autowiring-type>
|
||||
<autowiring-type>Baz</autowiring-type>
|
||||
</service>
|
||||
</services>
|
||||
</container>
|
@ -0,0 +1,6 @@
|
||||
<?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="bar" class="Bar" autowire="true" />
|
||||
</services>
|
||||
</container>
|
@ -0,0 +1,5 @@
|
||||
services:
|
||||
foo_service:
|
||||
class: FooClass
|
||||
# types is not an array
|
||||
autowiring_types: 1
|
@ -0,0 +1,5 @@
|
||||
services:
|
||||
foo_service:
|
||||
class: FooClass
|
||||
# autowiring_types is not a string
|
||||
autowiring_types: [ 1 ]
|
@ -0,0 +1,8 @@
|
||||
services:
|
||||
foo_service:
|
||||
class: FooClass
|
||||
autowiring_types: [ Foo, Bar ]
|
||||
|
||||
baz_service:
|
||||
class: Baz
|
||||
autowiring_types: Foo
|
@ -0,0 +1,4 @@
|
||||
services:
|
||||
bar_service:
|
||||
class: BarClass
|
||||
autowire: true
|
@ -494,4 +494,22 @@ class XmlFileLoaderTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertSame('Baz', $barConfigurator[0]->getClass());
|
||||
$this->assertSame('configureBar', $barConfigurator[1]);
|
||||
}
|
||||
|
||||
public function testType()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml'));
|
||||
$loader->load('services22.xml');
|
||||
|
||||
$this->assertEquals(array('Bar', 'Baz'), $container->getDefinition('foo')->getAutowiringTypes());
|
||||
}
|
||||
|
||||
public function testAutowire()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml'));
|
||||
$loader->load('services23.xml');
|
||||
|
||||
$this->assertTrue($container->getDefinition('bar')->isAutowired());
|
||||
}
|
||||
}
|
||||
|
@ -282,4 +282,41 @@ class YamlFileLoaderTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertEquals(array(true), $definition->getArguments());
|
||||
$this->assertEquals(array('manager' => array(array('alias' => 'user'))), $definition->getTags());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException
|
||||
*/
|
||||
public function testTypesNotArray()
|
||||
{
|
||||
$loader = new YamlFileLoader(new ContainerBuilder(), new FileLocator(self::$fixturesPath.'/yaml'));
|
||||
$loader->load('bad_types1.yml');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException
|
||||
*/
|
||||
public function testTypeNotString()
|
||||
{
|
||||
$loader = new YamlFileLoader(new ContainerBuilder(), new FileLocator(self::$fixturesPath.'/yaml'));
|
||||
$loader->load('bad_types2.yml');
|
||||
}
|
||||
|
||||
public function testTypes()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml'));
|
||||
$loader->load('services22.yml');
|
||||
|
||||
$this->assertEquals(array('Foo', 'Bar'), $container->getDefinition('foo_service')->getAutowiringTypes());
|
||||
$this->assertEquals(array('Foo'), $container->getDefinition('baz_service')->getAutowiringTypes());
|
||||
}
|
||||
|
||||
public function testAutowire()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml'));
|
||||
$loader->load('services23.yml');
|
||||
|
||||
$this->assertTrue($container->getDefinition('bar_service')->isAutowired());
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user