Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 1d4d6e7

Browse filesBrowse files
[DI] Fix missing DefinitionDecorator resolution in ContainerBuilder::createService()
1 parent 05c3e86 commit 1d4d6e7
Copy full SHA for 1d4d6e7

File tree

4 files changed

+132
-89
lines changed
Filter options

4 files changed

+132
-89
lines changed

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Compiler/ResolveDefinitionTemplatesPass.php
+1-89Lines changed: 1 addition & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -124,95 +124,7 @@ private function doResolveDefinition(ContainerBuilder $container, DefinitionDeco
124124
}
125125

126126
$this->compiler->addLogMessage($this->formatter->formatResolveInheritance($this, $this->currentId, $parent));
127-
$def = new Definition();
128-
129-
// merge in parent definition
130-
// purposely ignored attributes: abstract, tags
131-
$def->setClass($parentDef->getClass());
132-
$def->setArguments($parentDef->getArguments());
133-
$def->setMethodCalls($parentDef->getMethodCalls());
134-
$def->setProperties($parentDef->getProperties());
135-
$def->setAutowiringTypes($parentDef->getAutowiringTypes());
136-
if ($parentDef->isDeprecated()) {
137-
$def->setDeprecated(true, $parentDef->getDeprecationMessage('%service_id%'));
138-
}
139-
$def->setFactory($parentDef->getFactory());
140-
$def->setConfigurator($parentDef->getConfigurator());
141-
$def->setFile($parentDef->getFile());
142-
$def->setPublic($parentDef->isPublic());
143-
$def->setLazy($parentDef->isLazy());
144-
$def->setAutowired($parentDef->isAutowired());
145-
146-
// overwrite with values specified in the decorator
147-
$changes = $definition->getChanges();
148-
if (isset($changes['class'])) {
149-
$def->setClass($definition->getClass());
150-
}
151-
if (isset($changes['factory'])) {
152-
$def->setFactory($definition->getFactory());
153-
}
154-
if (isset($changes['configurator'])) {
155-
$def->setConfigurator($definition->getConfigurator());
156-
}
157-
if (isset($changes['file'])) {
158-
$def->setFile($definition->getFile());
159-
}
160-
if (isset($changes['public'])) {
161-
$def->setPublic($definition->isPublic());
162-
}
163-
if (isset($changes['lazy'])) {
164-
$def->setLazy($definition->isLazy());
165-
}
166-
if (isset($changes['deprecated'])) {
167-
$def->setDeprecated($definition->isDeprecated(), $definition->getDeprecationMessage('%service_id%'));
168-
}
169-
if (isset($changes['autowire'])) {
170-
$def->setAutowired($definition->isAutowired());
171-
}
172-
if (isset($changes['decorated_service'])) {
173-
$decoratedService = $definition->getDecoratedService();
174-
if (null === $decoratedService) {
175-
$def->setDecoratedService($decoratedService);
176-
} else {
177-
$def->setDecoratedService($decoratedService[0], $decoratedService[1], $decoratedService[2]);
178-
}
179-
}
180-
181-
// merge arguments
182-
foreach ($definition->getArguments() as $k => $v) {
183-
if (is_numeric($k)) {
184-
$def->addArgument($v);
185-
continue;
186-
}
187-
188-
if (0 !== strpos($k, 'index_')) {
189-
throw new RuntimeException(sprintf('Invalid argument key "%s" found.', $k));
190-
}
191-
192-
$index = (int) substr($k, strlen('index_'));
193-
$def->replaceArgument($index, $v);
194-
}
195-
196-
// merge properties
197-
foreach ($definition->getProperties() as $k => $v) {
198-
$def->setProperty($k, $v);
199-
}
200-
201-
// append method calls
202-
if (count($calls = $definition->getMethodCalls()) > 0) {
203-
$def->setMethodCalls(array_merge($def->getMethodCalls(), $calls));
204-
}
205-
206-
// merge autowiring types
207-
foreach ($definition->getAutowiringTypes() as $autowiringType) {
208-
$def->addAutowiringType($autowiringType);
209-
}
210-
211-
// these attributes are always taken from the child
212-
$def->setAbstract($definition->isAbstract());
213-
$def->setShared($definition->isShared());
214-
$def->setTags($definition->getTags());
215127

216-
return $def;
128+
return $definition->resolveChanges($parentDef);
217129
}
218130
}

‎src/Symfony/Component/DependencyInjection/ContainerBuilder.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/ContainerBuilder.php
+17Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -835,6 +835,10 @@ public function findDefinition($id)
835835
*/
836836
private function createService(Definition $definition, $id, $tryProxy = true)
837837
{
838+
if ($definition instanceof DefinitionDecorator) {
839+
$definition = $this->resolveDefinitionDecorator($definition, $id);
840+
}
841+
838842
if ($definition->isSynthetic()) {
839843
throw new RuntimeException(sprintf('You have requested a synthetic service ("%s"). The DIC does not know how to construct this service.', $id));
840844
}
@@ -1120,6 +1124,19 @@ private function callMethod($service, $call)
11201124
call_user_func_array(array($service, $call[0]), $this->resolveServices($this->getParameterBag()->unescapeValue($this->getParameterBag()->resolveValue($call[1]))));
11211125
}
11221126

1127+
private function resolveDefinitionDecorator(DefinitionDecorator $definition, $id)
1128+
{
1129+
if (!$this->has($parent = $definition->getParent())) {
1130+
throw new RuntimeException(sprintf('Service "%s": Parent definition "%s" does not exist.', $id, $parent));
1131+
}
1132+
$parentDef = $this->findDefinition($parent);
1133+
if ($parentDef instanceof DefinitionDecorator) {
1134+
$parentDef = $this->resolveDefinitionDecorator($parentDef, $parent);
1135+
}
1136+
1137+
return $definition->resolveChanges($parentDef);
1138+
}
1139+
11231140
/**
11241141
* Shares a given service in the container.
11251142
*

‎src/Symfony/Component/DependencyInjection/DefinitionDecorator.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/DefinitionDecorator.php
+103Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
1515
use Symfony\Component\DependencyInjection\Exception\OutOfBoundsException;
16+
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
1617

1718
/**
1819
* This definition decorates another definition.
@@ -196,4 +197,106 @@ public function replaceArgument($index, $value)
196197

197198
return $this;
198199
}
200+
201+
/**
202+
* Creates a new Definition by merging the current decorator with the given parent definition.
203+
*
204+
* @return Definition
205+
*/
206+
public function resolveChanges(Definition $parentDef)
207+
{
208+
if ($parentDef instanceof self) {
209+
throw new InvalidArgumentException('$parenfDef must be a resolved Definition.');
210+
}
211+
$def = new Definition();
212+
213+
// merge in parent definition
214+
// purposely ignored attributes: abstract, tags
215+
$def->setClass($parentDef->getClass());
216+
$def->setArguments($parentDef->getArguments());
217+
$def->setMethodCalls($parentDef->getMethodCalls());
218+
$def->setProperties($parentDef->getProperties());
219+
$def->setAutowiringTypes($parentDef->getAutowiringTypes());
220+
if ($parentDef->isDeprecated()) {
221+
$def->setDeprecated(true, $parentDef->getDeprecationMessage('%service_id%'));
222+
}
223+
$def->setFactory($parentDef->getFactory());
224+
$def->setConfigurator($parentDef->getConfigurator());
225+
$def->setFile($parentDef->getFile());
226+
$def->setPublic($parentDef->isPublic());
227+
$def->setLazy($parentDef->isLazy());
228+
$def->setAutowired($parentDef->isAutowired());
229+
230+
// overwrite with values specified in the decorator
231+
$changes = $this->getChanges();
232+
if (isset($changes['class'])) {
233+
$def->setClass($this->getClass());
234+
}
235+
if (isset($changes['factory'])) {
236+
$def->setFactory($this->getFactory());
237+
}
238+
if (isset($changes['configurator'])) {
239+
$def->setConfigurator($this->getConfigurator());
240+
}
241+
if (isset($changes['file'])) {
242+
$def->setFile($this->getFile());
243+
}
244+
if (isset($changes['public'])) {
245+
$def->setPublic($this->isPublic());
246+
}
247+
if (isset($changes['lazy'])) {
248+
$def->setLazy($this->isLazy());
249+
}
250+
if (isset($changes['deprecated'])) {
251+
$def->setDeprecated($this->isDeprecated(), $this->getDeprecationMessage('%service_id%'));
252+
}
253+
if (isset($changes['autowire'])) {
254+
$def->setAutowired($this->isAutowired());
255+
}
256+
if (isset($changes['decorated_service'])) {
257+
$decoratedService = $this->getDecoratedService();
258+
if (null === $decoratedService) {
259+
$def->setDecoratedService($decoratedService);
260+
} else {
261+
$def->setDecoratedService($decoratedService[0], $decoratedService[1], $decoratedService[2]);
262+
}
263+
}
264+
265+
// merge arguments
266+
foreach ($this->getArguments() as $k => $v) {
267+
if (is_numeric($k)) {
268+
$def->addArgument($v);
269+
continue;
270+
}
271+
272+
if (0 !== strpos($k, 'index_')) {
273+
throw new RuntimeException(sprintf('Invalid argument key "%s" found.', $k));
274+
}
275+
276+
$index = (int) substr($k, strlen('index_'));
277+
$def->replaceArgument($index, $v);
278+
}
279+
280+
// merge properties
281+
foreach ($this->getProperties() as $k => $v) {
282+
$def->setProperty($k, $v);
283+
}
284+
285+
// append method calls
286+
if (count($calls = $this->getMethodCalls()) > 0) {
287+
$def->setMethodCalls(array_merge($def->getMethodCalls(), $calls));
288+
}
289+
290+
// merge autowiring types
291+
foreach ($this->getAutowiringTypes() as $autowiringType) {
292+
$def->addAutowiringType($autowiringType);
293+
}
294+
295+
// these attributes are always taken from the child
296+
$def->setAbstract($this->isAbstract());
297+
$def->setShared($this->isShared());
298+
$def->setTags($this->getTags());
299+
300+
return $def;
301+
}
199302
}

‎src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php
+11Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use Symfony\Component\DependencyInjection\ContainerBuilder;
2121
use Symfony\Component\DependencyInjection\ContainerInterface;
2222
use Symfony\Component\DependencyInjection\Definition;
23+
use Symfony\Component\DependencyInjection\DefinitionDecorator;
2324
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
2425
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
2526
use Symfony\Component\DependencyInjection\Loader\ClosureLoader;
@@ -412,6 +413,16 @@ public function testResolveServices()
412413
$this->assertEquals($builder->get('foo'), $builder->resolveServices(new Expression('service("foo")')), '->resolveServices() resolves expressions');
413414
}
414415

416+
public function testResolveServicesWithDecoratedDefinition()
417+
{
418+
$builder = new ContainerBuilder();
419+
$builder->setDefinition('grandpa', new Definition('stdClass'));
420+
$builder->setDefinition('parent', new DefinitionDecorator('grandpa'));
421+
$builder->setDefinition('foo', new DefinitionDecorator('parent'));
422+
423+
$this->assertInstanceOf('stdClass', $builder->get('foo'));
424+
}
425+
415426
public function testMerge()
416427
{
417428
$container = new ContainerBuilder(new ParameterBag(array('bar' => 'foo')));

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.