Skip to content

Commit 9e70cd1

Browse files
committed
Merge branch '3.3' into 3.4
* 3.3: [DI] Fix deep-inlining of non-shared refs parse newlines in quoted multiline strings Fix collision between view properties and form fields
2 parents 694eefa + 785114b commit 9e70cd1

File tree

2 files changed

+90
-8
lines changed

2 files changed

+90
-8
lines changed

Compiler/InlineServiceDefinitionsPass.php

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
1515
use Symfony\Component\DependencyInjection\Definition;
16+
use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
1617
use Symfony\Component\DependencyInjection\Reference;
1718

1819
/**
@@ -23,6 +24,7 @@
2324
class InlineServiceDefinitionsPass extends AbstractRecursivePass implements RepeatablePassInterface
2425
{
2526
private $repeatedPass;
27+
private $cloningIds = array();
2628
private $inlinedServiceIds = array();
2729

2830
/**
@@ -58,18 +60,44 @@ protected function processValue($value, $isRoot = false)
5860
// Reference found in ArgumentInterface::getValues() are not inlineable
5961
return $value;
6062
}
61-
if ($value instanceof Reference && $this->container->hasDefinition($id = (string) $value)) {
62-
$definition = $this->container->getDefinition($id);
6363

64-
if ($this->isInlineableDefinition($id, $definition, $this->container->getCompiler()->getServiceReferenceGraph())) {
65-
$this->container->log($this, sprintf('Inlined service "%s" to "%s".', $id, $this->currentId));
66-
$this->inlinedServiceIds[$id][] = $this->currentId;
67-
68-
return $definition->isShared() ? $definition : clone $definition;
64+
if ($value instanceof Definition && $this->cloningIds) {
65+
if ($value->isShared()) {
66+
return $value;
6967
}
68+
$value = clone $value;
69+
}
70+
71+
if (!$value instanceof Reference || !$this->container->hasDefinition($id = (string) $value)) {
72+
return parent::processValue($value, $isRoot);
73+
}
74+
75+
$definition = $this->container->getDefinition($id);
76+
77+
if (!$this->isInlineableDefinition($id, $definition, $this->container->getCompiler()->getServiceReferenceGraph())) {
78+
return $value;
7079
}
7180

72-
return parent::processValue($value, $isRoot);
81+
$this->container->log($this, sprintf('Inlined service "%s" to "%s".', $id, $this->currentId));
82+
$this->inlinedServiceIds[$id][] = $this->currentId;
83+
84+
if ($definition->isShared()) {
85+
return $definition;
86+
}
87+
88+
if (isset($this->cloningIds[$id])) {
89+
$ids = array_keys($this->cloningIds);
90+
$ids[] = $id;
91+
92+
throw new ServiceCircularReferenceException($id, array_slice($ids, array_search($id, $ids)));
93+
}
94+
95+
$this->cloningIds[$id] = true;
96+
try {
97+
return $this->processValue($definition);
98+
} finally {
99+
unset($this->cloningIds[$id]);
100+
}
73101
}
74102

75103
/**

Tests/Compiler/InlineServiceDefinitionsPassTest.php

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,60 @@ public function testProcessInlinesMixedServicesLoop()
111111
$this->assertEquals($container->getDefinition('foo')->getArgument(0), $container->getDefinition('bar'));
112112
}
113113

114+
/**
115+
* @expectedException \Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException
116+
* @expectedExceptionMessage Circular reference detected for service "bar", path: "bar -> foo -> bar".
117+
*/
118+
public function testProcessThrowsOnNonSharedLoops()
119+
{
120+
$container = new ContainerBuilder();
121+
$container
122+
->register('foo')
123+
->addArgument(new Reference('bar'))
124+
->setShared(false)
125+
;
126+
$container
127+
->register('bar')
128+
->setShared(false)
129+
->addMethodCall('setFoo', array(new Reference('foo')))
130+
;
131+
132+
$this->process($container);
133+
}
134+
135+
public function testProcessNestedNonSharedServices()
136+
{
137+
$container = new ContainerBuilder();
138+
$container
139+
->register('foo')
140+
->addArgument(new Reference('bar1'))
141+
->addArgument(new Reference('bar2'))
142+
;
143+
$container
144+
->register('bar1')
145+
->setShared(false)
146+
->addArgument(new Reference('baz'))
147+
;
148+
$container
149+
->register('bar2')
150+
->setShared(false)
151+
->addArgument(new Reference('baz'))
152+
;
153+
$container
154+
->register('baz')
155+
->setShared(false)
156+
;
157+
158+
$this->process($container);
159+
160+
$baz1 = $container->getDefinition('foo')->getArgument(0)->getArgument(0);
161+
$baz2 = $container->getDefinition('foo')->getArgument(1)->getArgument(0);
162+
163+
$this->assertEquals($container->getDefinition('baz'), $baz1);
164+
$this->assertEquals($container->getDefinition('baz'), $baz2);
165+
$this->assertNotSame($baz1, $baz2);
166+
}
167+
114168
public function testProcessInlinesIfMultipleReferencesButAllFromTheSameDefinition()
115169
{
116170
$container = new ContainerBuilder();

0 commit comments

Comments
 (0)