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\Argument\BoundArgument;
16 use Symfony\Component\DependencyInjection\ChildDefinition;
17 use Symfony\Component\DependencyInjection\Compiler\ResolveChildDefinitionsPass;
18 use Symfony\Component\DependencyInjection\Compiler\ResolveInstanceofConditionalsPass;
19 use Symfony\Component\DependencyInjection\ContainerBuilder;
21 class ResolveInstanceofConditionalsPassTest extends TestCase
23 public function testProcess()
25 $container = new ContainerBuilder();
26 $def = $container->register('foo', self::class)->addTag('tag')->setAutowired(true)->setChanges(array());
27 $def->setInstanceofConditionals(array(
28 parent::class => (new ChildDefinition(''))->setProperty('foo', 'bar')->addTag('baz', array('attr' => 123)),
31 (new ResolveInstanceofConditionalsPass())->process($container);
33 $parent = 'instanceof.'.parent::class.'.0.foo';
34 $def = $container->getDefinition('foo');
35 $this->assertEmpty($def->getInstanceofConditionals());
36 $this->assertInstanceOf(ChildDefinition::class, $def);
37 $this->assertTrue($def->isAutowired());
38 $this->assertSame($parent, $def->getParent());
39 $this->assertSame(array('tag' => array(array()), 'baz' => array(array('attr' => 123))), $def->getTags());
41 $parent = $container->getDefinition($parent);
42 $this->assertSame(array('foo' => 'bar'), $parent->getProperties());
43 $this->assertSame(array(), $parent->getTags());
46 public function testProcessInheritance()
48 $container = new ContainerBuilder();
51 ->register('parent', parent::class)
52 ->addMethodCall('foo', array('foo'));
53 $def->setInstanceofConditionals(array(
54 parent::class => (new ChildDefinition(''))->addMethodCall('foo', array('bar')),
57 $def = (new ChildDefinition('parent'))->setClass(self::class);
58 $container->setDefinition('child', $def);
60 (new ResolveInstanceofConditionalsPass())->process($container);
61 (new ResolveChildDefinitionsPass())->process($container);
64 array('foo', array('bar')),
65 array('foo', array('foo')),
68 $this->assertSame($expected, $container->getDefinition('parent')->getMethodCalls());
69 $this->assertSame($expected, $container->getDefinition('child')->getMethodCalls());
72 public function testProcessDoesReplaceShared()
74 $container = new ContainerBuilder();
76 $def = $container->register('foo', 'stdClass');
77 $def->setInstanceofConditionals(array(
78 'stdClass' => (new ChildDefinition(''))->setShared(false),
81 (new ResolveInstanceofConditionalsPass())->process($container);
83 $def = $container->getDefinition('foo');
84 $this->assertFalse($def->isShared());
87 public function testProcessHandlesMultipleInheritance()
89 $container = new ContainerBuilder();
91 $def = $container->register('foo', self::class)->setShared(true);
93 $def->setInstanceofConditionals(array(
94 parent::class => (new ChildDefinition(''))->setLazy(true)->setShared(false),
95 self::class => (new ChildDefinition(''))->setAutowired(true),
98 (new ResolveInstanceofConditionalsPass())->process($container);
99 (new ResolveChildDefinitionsPass())->process($container);
101 $def = $container->getDefinition('foo');
102 $this->assertTrue($def->isAutowired());
103 $this->assertTrue($def->isLazy());
104 $this->assertTrue($def->isShared());
107 public function testProcessUsesAutoconfiguredInstanceof()
109 $container = new ContainerBuilder();
110 $def = $container->register('normal_service', self::class);
111 $def->setInstanceofConditionals(array(
112 parent::class => (new ChildDefinition(''))
113 ->addTag('local_instanceof_tag')
114 ->setFactory('locally_set_factory'),
116 $def->setAutoconfigured(true);
117 $container->registerForAutoconfiguration(parent::class)
118 ->addTag('autoconfigured_tag')
120 ->setFactory('autoconfigured_factory');
122 (new ResolveInstanceofConditionalsPass())->process($container);
123 (new ResolveChildDefinitionsPass())->process($container);
125 $def = $container->getDefinition('normal_service');
126 // autowired thanks to the autoconfigured instanceof
127 $this->assertTrue($def->isAutowired());
128 // factory from the specific instanceof overrides global one
129 $this->assertEquals('locally_set_factory', $def->getFactory());
130 // tags are merged, the locally set one is first
131 $this->assertSame(array('local_instanceof_tag' => array(array()), 'autoconfigured_tag' => array(array())), $def->getTags());
134 public function testAutoconfigureInstanceofDoesNotDuplicateTags()
136 $container = new ContainerBuilder();
137 $def = $container->register('normal_service', self::class);
139 ->addTag('duplicated_tag')
140 ->addTag('duplicated_tag', array('and_attributes' => 1))
142 $def->setInstanceofConditionals(array(
143 parent::class => (new ChildDefinition(''))->addTag('duplicated_tag'),
145 $def->setAutoconfigured(true);
146 $container->registerForAutoconfiguration(parent::class)
147 ->addTag('duplicated_tag', array('and_attributes' => 1))
150 (new ResolveInstanceofConditionalsPass())->process($container);
151 (new ResolveChildDefinitionsPass())->process($container);
153 $def = $container->getDefinition('normal_service');
154 $this->assertSame(array('duplicated_tag' => array(array(), array('and_attributes' => 1))), $def->getTags());
157 public function testProcessDoesNotUseAutoconfiguredInstanceofIfNotEnabled()
159 $container = new ContainerBuilder();
160 $def = $container->register('normal_service', self::class);
161 $def->setInstanceofConditionals(array(
162 parent::class => (new ChildDefinition(''))
165 $container->registerForAutoconfiguration(parent::class)
166 ->setAutowired(true);
168 (new ResolveInstanceofConditionalsPass())->process($container);
169 (new ResolveChildDefinitionsPass())->process($container);
171 $def = $container->getDefinition('normal_service');
172 $this->assertFalse($def->isAutowired());
176 * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
177 * @expectedExceptionMessage "App\FakeInterface" is set as an "instanceof" conditional, but it does not exist.
179 public function testBadInterfaceThrowsException()
181 $container = new ContainerBuilder();
182 $def = $container->register('normal_service', self::class);
183 $def->setInstanceofConditionals(array(
184 'App\\FakeInterface' => (new ChildDefinition(''))
188 (new ResolveInstanceofConditionalsPass())->process($container);
191 public function testBadInterfaceForAutomaticInstanceofIsOk()
193 $container = new ContainerBuilder();
194 $container->register('normal_service', self::class)
195 ->setAutoconfigured(true);
196 $container->registerForAutoconfiguration('App\\FakeInterface')
197 ->setAutowired(true);
199 (new ResolveInstanceofConditionalsPass())->process($container);
200 $this->assertTrue($container->hasDefinition('normal_service'));
204 * @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException
205 * @expectedExceptionMessage Autoconfigured instanceof for type "PHPUnit\Framework\TestCase" defines method calls but these are not supported and should be removed.
207 public function testProcessThrowsExceptionForAutoconfiguredCalls()
209 $container = new ContainerBuilder();
210 $container->registerForAutoconfiguration(parent::class)
211 ->addMethodCall('setFoo');
213 (new ResolveInstanceofConditionalsPass())->process($container);
217 * @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException
218 * @expectedExceptionMessage Autoconfigured instanceof for type "PHPUnit\Framework\TestCase" defines arguments but these are not supported and should be removed.
220 public function testProcessThrowsExceptionForArguments()
222 $container = new ContainerBuilder();
223 $container->registerForAutoconfiguration(parent::class)
224 ->addArgument('bar');
226 (new ResolveInstanceofConditionalsPass())->process($container);
229 public function testMergeReset()
231 $container = new ContainerBuilder();
234 ->register('bar', self::class)
236 ->addMethodCall('setB')
237 ->setDecoratedService('foo')
239 ->setInstanceofConditionals(array(
240 parent::class => (new ChildDefinition(''))->addTag('bar'),
244 (new ResolveInstanceofConditionalsPass())->process($container);
246 $abstract = $container->getDefinition('abstract.instanceof.bar');
248 $this->assertEmpty($abstract->getArguments());
249 $this->assertEmpty($abstract->getMethodCalls());
250 $this->assertNull($abstract->getDecoratedService());
251 $this->assertEmpty($abstract->getTags());
252 $this->assertTrue($abstract->isAbstract());
255 public function testBindings()
257 $container = new ContainerBuilder();
258 $def = $container->register('foo', self::class)->setBindings(array('$toto' => 123));
259 $def->setInstanceofConditionals(array(parent::class => new ChildDefinition('')));
261 (new ResolveInstanceofConditionalsPass())->process($container);
263 $bindings = $container->getDefinition('foo')->getBindings();
264 $this->assertSame(array('$toto'), array_keys($bindings));
265 $this->assertInstanceOf(BoundArgument::class, $bindings['$toto']);
266 $this->assertSame(123, $bindings['$toto']->getValues()[0]);