8000 [DependencyInjection] Allow anonymous DefinitionDecorator resolving · symfony/symfony@de9335b · GitHub
[go: up one dir, main page]

Skip to content

Commit de9335b

Browse files
[DependencyInjection] Allow anonymous DefinitionDecorator resolving
1 parent bd66434 commit de9335b

File tree

2 files changed

+73
-15
lines changed

2 files changed

+73
-15
lines changed

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

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,13 @@
2121
* merged Definition instance.
2222
*
2323
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
24+
* @author Nicolas Grekas <p@tchwork.com>
2425
*/
2526
class ResolveDefinitionTemplatesPass implements CompilerPassInterface
2627
{
27-
private $container;
2828
private $compiler;
2929
private $formatter;
30+
private $currentId;
3031

3132
/**
3233
* Process the ContainerBuilder to replace DefinitionDecorator instances with their real Definition instances.
@@ -35,44 +36,78 @@ class ResolveDefinitionTemplatesPass implements CompilerPassInterface
3536
*/
3637
public function process(ContainerBuilder $container)
3738
{
38-
$this->container = $container;
3939
$this->compiler = $container->getCompiler();
4040
$this->formatter = $this->compiler->getLoggingFormatter();
4141

4242
foreach ($container->getDefinitions() as $id => $definition) {
43+
$this->currentId = $id;
44+
4345
// yes, we are specifically fetching the definition from the
4446
// container to ensure we are not operating on stale data
4547
$definition = $container->getDefinition($id);
46-
if (!$definition instanceof DefinitionDecorator || $definition->isAbstract()) {
47-
continue;
48+
if ($definition instanceof DefinitionDecorator) {
49+
$definition = $this->resolveDefinition($container, $definition);
50+
$container->setDefinition($id, $definition);
4851
}
4952

50-
$this->resolveDefinition($id, $definition);
53+
$definition->setArguments($this->resolveArguments($container, $definition->getArguments()));
54+
$definition->setMethodCalls($this->resolveArguments($container, $definition->getMethodCalls()));
55+
$definition->setProperties($this->resolveArguments($container, $definition->getProperties()));
5156
}
5257
}
5358

59+
/**
60+
* Resolves definition decorator arguments.
61+
*
62+
* @param ContainerBuilder $container The ContainerBuilder
63+
* @param array $arguments An array of arguments
64+
*
65+
* @return array
66+
*/
67+
private function resolveArguments(ContainerBuilder $container, array $arguments)
68+
{
69+
foreach ($arguments as $k => $argument) {
70+
if (is_array($argument)) {
71+
$arguments[$k] = $this->resolveArguments($container, $argument);
72+
} elseif ($argument instanceof Definition) {
73+
if ($argument instanceof DefinitionDecorator) {
74+
$arguments[$k] = $argument = $this->resolveDefinition($container, $argument);
75+
}
76+
$argument->setArguments($this->resolveArguments($container, $argument->getArguments()));
77+
$argument->setMethodCalls($this->resolveArguments($container, $argument->getMethodCalls()));
78+
$argument->setProperties($this->resolveArguments($container, $argument->getProperties()));
79+
}
80+
}
81+
82+
return $arguments;
83+
}
84+
5485
/**
5586
* Resolves the definition.
5687
*
57-
* @param string $id The definition identifier
88+
* @param ContainerBuilder $container The ContainerBuilder
5889
* @param DefinitionDecorator $definition
5990
*
6091
* @return Definition
6192
*
6293
* @throws \RuntimeException When the definition is invalid
6394
*/
64-
private function resolveDefinition($id, DefinitionDecorator $definition)
95+
private function resolveDefinition(ContainerBuilder $container, DefinitionDecorator $definition)
6596
{
66-
if (!$this->container->hasDefinition($parent = $definition->getParent())) {
67-
throw new RuntimeException(sprintf('The parent definition "%s" defined for definition "%s" does not exist.', $parent, $id));
97+
if (!$container->hasDefinition($parent = $definition->getParent())) {
98+
throw new RuntimeException(sprintf('The parent definition "%s" defined for definition "%s" does not exist.', $parent, $this->currentId));
6899
}
69100

70-
$parentDef = $this->container->getDefinition($parent);
101+
$parentDef = $container->getDefinition($parent);
71102
if ($parentDef instanceof DefinitionDecorator) {
72-
$parentDef = $this->resolveDefinition($parent, $parentDef);
103+
$id = $this->currentId;
104+
$this->currentId = $parent;
105+
$parentDef = $this->resolveDefinition($container, $parentDef);
106+
$container->setDefinition($parent, $parentDef);
107+
$this->currentId = $id;
73108
}
74109

75-
$this->compiler->addLogMessage($this->formatter->formatResolveInheritance($this, $id, $parent));
110+
$this->compiler->addLogMessage($this->formatter->formatResolveInheritance($this, $this->currentId, $parent));
76111
$def = new Definition();
77112

78113
// merge in parent definition
@@ -156,9 +191,6 @@ private function resolveDefinition($id, DefinitionDecorator $definition)
156191
$def->setScope($definition->getScope(false), false);
157192
$def->setTags($definition->getTags());
158193

159-
// set new definition on container
160-
$this->container->setDefinition($id, $def);
161-
162194
return $def;
163195
}
164196
}

src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveDefinitionTemplatesPassTest.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,32 @@ public function testSetLazyOnServiceIsParent()
176176
$this->assertTrue($container->getDefinition('child1')->isLazy());
177177
}
178178

179+
public function testDeepDefinitionsResolving()
180+
{
181+
$container = new ContainerBuilder();
182+
183+
$container->register('parent', 'parentClass');
184+
$container->register('sibling', 'siblingClass')
185+
->addArgument(new DefinitionDecorator('parent'))
186+
->setProperty('prop', new DefinitionDecorator('parent'))
187+
->addMethodCall('meth', array(new DefinitionDecorator('parent')))
188+
;
189+
190+
$this->process($container);
191+
192+
$argument = $container->getDefinition('sibling')->getArgument(0);
193+
$this->assertSame('Symfony\Component\DependencyInjection\Definition', get_class($argument));
194+
$this->assertSame('parentClass', $argument->getClass());
195+
196+
$properties = $container->getDefinition('sibling')->getProperties();
197+
$this->assertSame('Symfony\Component\DependencyInjection\Definition', get_class($properties['prop']));
198+
$this->assertSame('parentClass', $properties['prop']->getClass());
199+
200+
$methodCalls = $container->getDefinition('sibling')->getMethodCalls();
201+
$this->assertSame('Symfony\Component\DependencyInjection\Definition', get_class($methodCalls[0][1][0]));
202+
$this->assertSame('parentClass', $methodCalls[0][1][0]->getClass());
203+
}
204+
179205
protected function process(ContainerBuilder $container)
180206
{
181207
$pass = new ResolveDefinitionTemplatesPass();

0 commit comments

Comments
 (0)
0