4 * This file is part of the Symfony package.
6 * (c) Fabien Potencier <fabien@symfony.com>
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
12 namespace Symfony\Component\DependencyInjection\Tests\Compiler;
14 use PHPUnit\Framework\TestCase;
15 use Symfony\Component\DependencyInjection\ChildDefinition;
16 use Symfony\Component\DependencyInjection\Compiler\ResolveChildDefinitionsPass;
17 use Symfony\Component\DependencyInjection\Compiler\ResolveDefinitionTemplatesPass;
18 use Symfony\Component\DependencyInjection\ContainerBuilder;
20 class ResolveChildDefinitionsPassTest extends TestCase
22 public function testProcess()
24 $container = new ContainerBuilder();
25 $container->register('parent', 'foo')->setArguments(array('moo', 'b'))->setProperty('foo', 'moo');
26 $container->setDefinition('child', new ChildDefinition('parent'))
27 ->replaceArgument(0, 'a')
28 ->setProperty('foo', 'bar')
32 $this->process($container);
34 $def = $container->getDefinition('child');
35 $this->assertNotInstanceOf(ChildDefinition::class, $def);
36 $this->assertEquals('bar', $def->getClass());
37 $this->assertEquals(array('a', 'b'), $def->getArguments());
38 $this->assertEquals(array('foo' => 'bar'), $def->getProperties());
41 public function testProcessAppendsMethodCallsAlways()
43 $container = new ContainerBuilder();
47 ->addMethodCall('foo', array('bar'))
51 ->setDefinition('child', new ChildDefinition('parent'))
52 ->addMethodCall('bar', array('foo'))
55 $this->process($container);
57 $def = $container->getDefinition('child');
58 $this->assertEquals(array(
59 array('foo', array('bar')),
60 array('bar', array('foo')),
61 ), $def->getMethodCalls());
64 public function testProcessDoesNotCopyAbstract()
66 $container = new ContainerBuilder();
74 ->setDefinition('child', new ChildDefinition('parent'))
77 $this->process($container);
79 $def = $container->getDefinition('child');
80 $this->assertFalse($def->isAbstract());
83 public function testProcessDoesNotCopyShared()
85 $container = new ContainerBuilder();
93 ->setDefinition('child', new ChildDefinition('parent'))
96 $this->process($container);
98 $def = $container->getDefinition('child');
99 $this->assertTrue($def->isShared());
102 public function testProcessDoesNotCopyTags()
104 $container = new ContainerBuilder();
112 ->setDefinition('child', new ChildDefinition('parent'))
115 $this->process($container);
117 $def = $container->getDefinition('child');
118 $this->assertEquals(array(), $def->getTags());
121 public function testProcessDoesNotCopyDecoratedService()
123 $container = new ContainerBuilder();
127 ->setDecoratedService('foo')
131 ->setDefinition('child', new ChildDefinition('parent'))
134 $this->process($container);
136 $def = $container->getDefinition('child');
137 $this->assertNull($def->getDecoratedService());
140 public function testProcessDoesNotDropShared()
142 $container = new ContainerBuilder();
149 ->setDefinition('child', new ChildDefinition('parent'))
153 $this->process($container);
155 $def = $container->getDefinition('child');
156 $this->assertFalse($def->isShared());
159 public function testProcessHandlesMultipleInheritance()
161 $container = new ContainerBuilder();
164 ->register('parent', 'foo')
165 ->setArguments(array('foo', 'bar', 'c'))
169 ->setDefinition('child2', new ChildDefinition('child1'))
170 ->replaceArgument(1, 'b')
174 ->setDefinition('child1', new ChildDefinition('parent'))
175 ->replaceArgument(0, 'a')
178 $this->process($container);
180 $def = $container->getDefinition('child2');
181 $this->assertEquals(array('a', 'b', 'c'), $def->getArguments());
182 $this->assertEquals('foo', $def->getClass());
185 public function testSetLazyOnServiceHasParent()
187 $container = new ContainerBuilder();
189 $container->register('parent', 'stdClass');
191 $container->setDefinition('child1', new ChildDefinition('parent'))
195 $this->process($container);
197 $this->assertTrue($container->getDefinition('child1')->isLazy());
200 public function testSetLazyOnServiceIsParent()
202 $container = new ContainerBuilder();
204 $container->register('parent', 'stdClass')
208 $container->setDefinition('child1', new ChildDefinition('parent'));
210 $this->process($container);
212 $this->assertTrue($container->getDefinition('child1')->isLazy());
215 public function testSetAutowiredOnServiceHasParent()
217 $container = new ContainerBuilder();
219 $container->register('parent', 'stdClass')
223 $container->setDefinition('child1', new ChildDefinition('parent'))
224 ->setAutowired(false)
227 $this->process($container);
229 $this->assertFalse($container->getDefinition('child1')->isAutowired());
232 public function testSetAutowiredOnServiceIsParent()
234 $container = new ContainerBuilder();
236 $container->register('parent', 'stdClass')
240 $container->setDefinition('child1', new ChildDefinition('parent'));
242 $this->process($container);
244 $this->assertTrue($container->getDefinition('child1')->isAutowired());
247 public function testDeepDefinitionsResolving()
249 $container = new ContainerBuilder();
251 $container->register('parent', 'parentClass');
252 $container->register('sibling', 'siblingClass')
253 ->setConfigurator(new ChildDefinition('parent'), 'foo')
254 ->setFactory(array(new ChildDefinition('parent'), 'foo'))
255 ->addArgument(new ChildDefinition('parent'))
256 ->setProperty('prop', new ChildDefinition('parent'))
257 ->addMethodCall('meth', array(new ChildDefinition('parent')))
260 $this->process($container);
262 $configurator = $container->getDefinition('sibling')->getConfigurator();
263 $this->assertSame('Symfony\Component\DependencyInjection\Definition', \get_class($configurator));
264 $this->assertSame('parentClass', $configurator->getClass());
266 $factory = $container->getDefinition('sibling')->getFactory();
267 $this->assertSame('Symfony\Component\DependencyInjection\Definition', \get_class($factory[0]));
268 $this->assertSame('parentClass', $factory[0]->getClass());
270 $argument = $container->getDefinition('sibling')->getArgument(0);
271 $this->assertSame('Symfony\Component\DependencyInjection\Definition', \get_class($argument));
272 $this->assertSame('parentClass', $argument->getClass());
274 $properties = $container->getDefinition('sibling')->getProperties();
275 $this->assertSame('Symfony\Component\DependencyInjection\Definition', \get_class($properties['prop']));
276 $this->assertSame('parentClass', $properties['prop']->getClass());
278 $methodCalls = $container->getDefinition('sibling')->getMethodCalls();
279 $this->assertSame('Symfony\Component\DependencyInjection\Definition', \get_class($methodCalls[0][1][0]));
280 $this->assertSame('parentClass', $methodCalls[0][1][0]->getClass());
283 public function testSetDecoratedServiceOnServiceHasParent()
285 $container = new ContainerBuilder();
287 $container->register('parent', 'stdClass');
289 $container->setDefinition('child1', new ChildDefinition('parent'))
290 ->setDecoratedService('foo', 'foo_inner', 5)
293 $this->process($container);
295 $this->assertEquals(array('foo', 'foo_inner', 5), $container->getDefinition('child1')->getDecoratedService());
298 public function testDecoratedServiceCopiesDeprecatedStatusFromParent()
300 $container = new ContainerBuilder();
301 $container->register('deprecated_parent')
302 ->setDeprecated(true)
305 $container->setDefinition('decorated_deprecated_parent', new ChildDefinition('deprecated_parent'));
307 $this->process($container);
309 $this->assertTrue($container->getDefinition('decorated_deprecated_parent')->isDeprecated());
312 public function testDecoratedServiceCanOverwriteDeprecatedParentStatus()
314 $container = new ContainerBuilder();
315 $container->register('deprecated_parent')
316 ->setDeprecated(true)
319 $container->setDefinition('decorated_deprecated_parent', new ChildDefinition('deprecated_parent'))
320 ->setDeprecated(false)
323 $this->process($container);
325 $this->assertFalse($container->getDefinition('decorated_deprecated_parent')->isDeprecated());
331 public function testProcessMergeAutowiringTypes()
333 $container = new ContainerBuilder();
337 ->addAutowiringType('Foo')
341 ->setDefinition('child', new ChildDefinition('parent'))
342 ->addAutowiringType('Bar')
345 $this->process($container);
347 $childDef = $container->getDefinition('child');
348 $this->assertEquals(array('Foo', 'Bar'), $childDef->getAutowiringTypes());
350 $parentDef = $container->getDefinition('parent');
351 $this->assertSame(array('Foo'), $parentDef->getAutowiringTypes());
354 public function testProcessResolvesAliases()
356 $container = new ContainerBuilder();
358 $container->register('parent', 'ParentClass');
359 $container->setAlias('parent_alias', 'parent');
360 $container->setDefinition('child', new ChildDefinition('parent_alias'));
362 $this->process($container);
364 $def = $container->getDefinition('child');
365 $this->assertSame('ParentClass', $def->getClass());
368 public function testProcessSetsArguments()
370 $container = new ContainerBuilder();
372 $container->register('parent', 'ParentClass')->setArguments(array(0));
373 $container->setDefinition('child', (new ChildDefinition('parent'))->setArguments(array(
379 $this->process($container);
381 $def = $container->getDefinition('child');
382 $this->assertSame(array(2, 1, 'foo' => 3), $def->getArguments());
385 public function testBindings()
387 $container = new ContainerBuilder();
389 $container->register('parent', 'stdClass')
390 ->setBindings(array('a' => '1', 'b' => '2'))
393 $child = $container->setDefinition('child', new ChildDefinition('parent'))
394 ->setBindings(array('b' => 'B', 'c' => 'C'))
397 $this->process($container);
400 foreach ($container->getDefinition('child')->getBindings() as $k => $v) {
401 $bindings[$k] = $v->getValues()[0];
403 $this->assertEquals(array('b' => 'B', 'c' => 'C', 'a' => '1'), $bindings);
406 public function testSetAutoconfiguredOnServiceIsParent()
408 $container = new ContainerBuilder();
410 $container->register('parent', 'stdClass')
411 ->setAutoconfigured(true)
414 $container->setDefinition('child1', new ChildDefinition('parent'));
416 $this->process($container);
418 $this->assertFalse($container->getDefinition('child1')->isAutoconfigured());
424 public function testAliasExistsForBackwardsCompatibility()
426 $this->assertInstanceOf(ResolveChildDefinitionsPass::class, new ResolveDefinitionTemplatesPass());
429 protected function process(ContainerBuilder $container)
431 $pass = new ResolveChildDefinitionsPass();
432 $pass->process($container);
436 * @expectedException \Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException
437 * @expectedExceptionMessageRegExp /^Circular reference detected for service "c", path: "c -> b -> a -> c"./
439 public function testProcessDetectsChildDefinitionIndirectCircularReference()
441 $container = new ContainerBuilder();
443 $container->register('a');
445 $container->setDefinition('b', new ChildDefinition('a'));
446 $container->setDefinition('c', new ChildDefinition('b'));
447 $container->setDefinition('a', new ChildDefinition('c'));
449 $this->process($container);