diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php new file mode 100644 index 000000000000..3b85543b8b95 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php @@ -0,0 +1,263 @@ + + * + * 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 + */ +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 + } + } +} diff --git a/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php b/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php index 2849dfe129a7..246529d865cd 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php @@ -50,6 +50,7 @@ public function __construct() new CheckDefinitionValidityPass(), new ResolveReferencesToAliasesPass(), new ResolveInvalidReferencesPass(), + new AutowirePass(), new AnalyzeServiceReferencesPass(true), new CheckCircularReferencesPass(), new CheckReferenceValidityPass(), diff --git a/src/Symfony/Component/DependencyInjection/Definition.php b/src/Symfony/Component/DependencyInjection/Definition.php index 9ce81e3a12cf..66ea2cc0e414 100644 --- a/src/Symfony/Component/DependencyInjection/Definition.php +++ b/src/Symfony/Component/DependencyInjection/Definition.php @@ -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 @@ public function getConfigurator() { 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]); + } } diff --git a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php index 8a0e4ac24a65..7fb98972c0c6 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php @@ -157,6 +157,10 @@ private function parseDefinition(\DOMElement $service, $file) } } + 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 @@ private function parseDefinition(\DOMElement $service, $file) $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; diff --git a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php index 19191a760c6c..3039885ec2fc 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php @@ -299,6 +299,28 @@ private function parseDefinition($id, $service, $file) $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); } diff --git a/src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd b/src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd index cbaa3606f7a0..3241c43c4099 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd +++ b/src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd @@ -85,6 +85,7 @@ + @@ -103,6 +104,7 @@ + diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php new file mode 100644 index 000000000000..3639a2138fad --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php @@ -0,0 +1,300 @@ + + * + * 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 + */ +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) + { + } +} diff --git a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php index 047a7cf3347f..ad83f8e0d13f 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php @@ -890,6 +890,19 @@ public function testLazyLoadedService() $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 @@ public function getFoobazService() throw new InactiveScopeException('foo', 'request'); } } + +class A +{ +} + +class B +{ + public function __construct(A $a) + { + } +} diff --git a/src/Symfony/Component/DependencyInjection/Tests/DefinitionTest.php b/src/Symfony/Component/DependencyInjection/Tests/DefinitionTest.php index ea3045df1acb..cb6344e49578 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/DefinitionTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/DefinitionTest.php @@ -394,4 +394,25 @@ public function testSetProperty() $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()); + } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services22.xml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services22.xml new file mode 100644 index 000000000000..fa79d389489f --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services22.xml @@ -0,0 +1,9 @@ + + + + + Bar + Baz + + + diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services23.xml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services23.xml new file mode 100644 index 000000000000..3f9e15fd499d --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services23.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/bad_types1.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/bad_types1.yml new file mode 100644 index 000000000000..891e01497cad --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/bad_types1.yml @@ -0,0 +1,5 @@ +services: + foo_service: + class: FooClass + # types is not an array + autowiring_types: 1 diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/bad_types2.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/bad_types2.yml new file mode 100644 index 000000000000..fb1d53e15101 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/bad_types2.yml @@ -0,0 +1,5 @@ +services: + foo_service: + class: FooClass + # autowiring_types is not a string + autowiring_types: [ 1 ] diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services22.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services22.yml new file mode 100644 index 000000000000..55d015baea0f --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services22.yml @@ -0,0 +1,8 @@ +services: + foo_service: + class: FooClass + autowiring_types: [ Foo, Bar ] + + baz_service: + class: Baz + autowiring_types: Foo diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services23.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services23.yml new file mode 100644 index 000000000000..1984c1771463 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services23.yml @@ -0,0 +1,4 @@ +services: + bar_service: + class: BarClass + autowire: true diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php index b717113bb436..723d30605ea4 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php @@ -494,4 +494,22 @@ public function testLoadInlinedServices() $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()); + } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php index 2d1b0b6956f7..8ab714e43a2c 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php @@ -282,4 +282,41 @@ public function testLoadYamlOnlyWithKeys() $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()); + } } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy