8000 bug #21741 [DI] Fix ordering of tags inheritance (nicolas-grekas) · symfony/symfony@f1f982d · GitHub
[go: up one dir, main page]

Skip to content

Commit f1f982d

Browse files
committed
bug #21741 [DI] Fix ordering of tags inheritance (nicolas-grekas)
This PR was merged into the 3.3-dev branch. Discussion ---------- [DI] Fix ordering of tags inheritance | Q | A | ------------- | --- | Branch? | master | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | - | License | MIT | Doc PR | - Tag inheritance should have predictable ordering, from child to parents. This PR also adds tests for ResolveDefinitionInheritancePass (heavily inspired by ResolveDefinitionTemplatePass). Commits ------- 18e7681 [DI] Fix ordering of tags inheritance
2 parents 29b5a6e + 18e7681 commit f1f982d

File tree

2 files changed

+195
-4
lines changed

2 files changed

+195
-4
lines changed

src/Symfony/Component/DependencyInjection/Compiler/ResolveDefinitionInheritancePass.php

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,14 @@ private function mergeDefinition(Definition $def, ChildDefinition $definition)
9393
$def->setAutowiredCalls(array_merge($autowiredCalls, $def->getAutowiredCalls()));
9494
}
9595

96-
// merge tags
97-
foreach ($definition->getTags() as $k => $v) {
98-
foreach ($v as $v) {
99-
$def->addTag($k, $v);
96+
// prepend instanceof tags
97+
$tailTags = $def->getTags();
98+
if ($headTags = $definition->getTags()) {
99+
$def->setTags($headTags);
100+
foreach ($tailTags as $k => $v) {
101+
foreach ($v as $v) {
102+
$def->addTag($k, $v);
103+
}
100104
}
101105
}
102106
}
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\DependencyInjection\Tests\Compiler;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\DependencyInjection\ChildDefinition;
16+
use Symfony\Component\DependencyInjection\Compiler\ResolveDefinitionInheritancePass;
17+
use Symfony\Component\DependencyInjection\ContainerBuilder;
18+
19+
class ResolveDefinitionInheritancePassTest extends TestCase
20+
{
21+
public function testProcess()
22+
{
23+
$container = new ContainerBuilder();
24+
$def = $container->register('parent', self::class)->setArguments(array('moo', 'b'))->setProperty('foo', 'moo');
25+
$def->setInstanceofConditionals(array(
26+
parent::class => (new ChildDefinition(''))
27+
->replaceArgument(0, 'a')
28+
->setProperty('foo', 'bar')
29+
->setClass('bar'),
30+
));
31+
32+
$this->process($container);
33+
34+
$this->assertEmpty($def->getInstanceofConditionals());
35+
$this->assertSame($def, $container->getDefinition('parent'));
36+
$this->assertEquals('bar', $def->getClass());
37+
$this->assertEquals(array('a', 'b'), $def->getArguments());
38+
$this->assertEquals(array('foo' => 'bar'), $def->getProperties());
39+
}
40+
41+
public function testProcessAppendsMethodCallsAlways()
42+
{
43+
$container = new ContainerBuilder();
44+
45+
$def = $container
46+
->register('parent', self::class)
47+
->addMethodCall('foo', array('bar'));
48+
49+
$def->setInstanceofConditionals(array(
50+
parent::class => (new ChildDefinition(''))
51+
->addMethodCall('bar', array('foo')),
52+
));
53+
54+
$this->process($container);
55+
56+
$this->assertEquals(array(
57+
array('foo', array('bar')),
58+
array('bar', array('foo')),
59+
), $container->getDefinition('parent')->getMethodCalls());
60+
}
61+
62+
public function testProcessDoesReplaceAbstract()
63+
{
64+
$container = new ContainerBuilder();
65+
66+
$def = $container->register('parent', 'stdClass');
67+
68+
$def->setInstanceofConditionals(array(
69+
'stdClass' => (new ChildDefinition(''))->setAbstract(true),
70+
));
71+
72+
$this->process($container);
73+
74+
$this->assertTrue($def->isAbstract());
75+
}
76+
77+
public function testProcessDoesReplaceShared()
78+
{
79+
$container = new ContainerBuilder();
80+
81+
$def = $container->register('parent', 'stdClass');
82+
83+
$def->setInstanceofConditionals(array(
84+
'stdClass' => (new ChildDefinition(''))->setShared(false),
85+
));
86+
87+
$this->process($container);
88+
89+
$this->assertFalse($def->isShared());
90+
}
91+
92+
public function testProcessHandlesMultipleInheritance()
93+
{
94+
$container = new ContainerBuilder();
95+
96+
$def = $container
97+
->register('parent', self::class)
98+
->setArguments(array('foo', 'bar', 'c'))
99+
;
100+
101+
$def->setInstanceofConditionals(array(
102+
parent::class => (new ChildDefinition(''))->replaceArgument(1, 'b'),
103+
self::class => (new ChildDefinition(''))->replaceArgument(0, 'a'),
104+
));
105+
106+
$this->process($container);
107+
108+
$this->assertEquals(array('a', 'b', 'c'), $def->getArguments());
109+
}
110+
111+
public function testSetLazyOnServiceHasParent()
112+
{
113+
$container = new ContainerBuilder();
114+
115+
$def = $container->register('parent', 'stdClass');
116+
117+
$def->setInstanceofConditionals(array(
118+
'stdClass' => (new ChildDefinition(''))->setLazy(true),
119+
));
120+
121+
$this->process($container);
122+
123+
$this->assertTrue($container->getDefinition('parent')->isLazy());
124+
}
125+
126+
public function testSetAutowiredOnServiceHasParent()
127+
{
128+
$container = new ContainerBuilder();
129+
130+
$def = $container->register('parent', 'stdClass')
131+
->setAutowiredCalls(array('foo'))
132+
;
133+
134+
$def->setInstanceofConditionals(array(
135+
'stdClass' => (new ChildDefinition(''))->setAutowiredCalls(array('bar')),
136+
));
137+
138+
$this->process($container);
139+
140+
$this->assertEquals(array('foo', 'bar'), $def->getAutowiredCalls());
141+
}
142+
143+
public function testProcessInheritTags()
144+
{
145+
$container = new ContainerBuilder();
146+
147+
$container->register('parent', self::class)->addTag('parent');
148+
149+
$def = $container->setDefinition('child', new ChildDefinition('parent'))
150+
->addTag('child')
151+
->setInheritTags(true)
152+
;
153+
154+
$def->setInstanceofConditionals(array(
155+
parent::class => (new ChildDefinition(''))->addTag('foo'),
156+
));
157+
158+
$this->process($container);
159+
160+
$t = array(array());
161+
$this->assertSame(array('foo' => $t, 'child' => $t, 'parent' => $t), $def->getTags());
162+
}
163+
164+
public function testProcessResolvesAliasesAndTags()
165+
{
166+
$container = new ContainerBuilder();
167+
168+
$container->register('parent', self::class);
169+
$container->setAlias('parent_alias', 'parent');
170+
$def = $container->setDefinition('child', new ChildDefinition('parent_alias'));
171+
$def->setInstanceofConditionals(array(
172+
parent::class => (new ChildDefinition(''))->addTag('foo'),
173+
));
174+
175+
$this->process($container);
176+
177+
$this->assertSame(array('foo' => array(array())), $def->getTags());
178+
$this->assertSame($def, $container->getDefinition('child'));
179+
$this->assertEmpty($def->getClass());
180+
}
181+
182+
protected function process(ContainerBuilder $container)
183+
{
184+
$pass = new ResolveDefinitionInheritancePass();
185+
$pass->process($container);
186+
}
187+
}

0 commit comments

Comments
 (0)
0