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)
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