Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 54a5b7b

Browse files
committed
Fix lazy service in non-constructors
1 parent b60bb6e commit 54a5b7b

File tree

8 files changed

+142
-39
lines changed

8 files changed

+142
-39
lines changed

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\DependencyInjection\Compiler;
1313

1414
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
15+
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
1516
use Symfony\Component\DependencyInjection\ContainerBuilder;
1617
use Symfony\Component\DependencyInjection\ContainerInterface;
1718
use Symfony\Component\DependencyInjection\Definition;
@@ -35,6 +36,7 @@ class AnalyzeServiceReferencesPass extends AbstractRecursivePass implements Repe
3536
private $hasProxyDumper;
3637
private $lazy;
3738
private $byConstructor;
39+
private $byFactory;
3840
private $definitions;
3941
private $aliases;
4042

@@ -66,6 +68,7 @@ public function process(ContainerBuilder $container)
6668
$this->graph->clear();
6769
$this->lazy = false;
6870
$this->byConstructor = false;
71+
$this->byFactory = false;
6972
$this->definitions = $container->getDefinitions();
7073
$this->aliases = $container->getAliases();
7174

@@ -87,7 +90,7 @@ protected function processValue($value, $isRoot = false)
8790
$inExpression = $this->inExpression();
8891

8992
if ($value instanceof ArgumentInterface) {
90-
$this->lazy = true;
93+
$this->lazy = !$value instanceof IteratorArgument || !$this->byFactory;
9194
parent::processValue($value->getValues());
9295
$this->lazy = $lazy;
9396

@@ -137,8 +140,13 @@ protected function processValue($value, $isRoot = false)
137140

138141
$byConstructor = $this->byConstructor;
139142
$this->byConstructor = $isRoot || $byConstructor;
143+
144+
$byFactory = $this->byFactory;
145+
$this->byFactory = true;
140146
$this->processValue($value->getFactory());
147+
$this->byFactory = $byFactory;
141148
$this->processValue($value->getArguments());
149+
$this->byFactory = false;
142150

143151
$properties = $value->getProperties();
144152
$setters = $value->getMethodCalls();

src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,7 @@ private function collectCircularReferences(string $sourceId, array $edges, array
420420
foreach ($edges as $edge) {
421421
$node = $edge->getDestNode();
422422
$id = $node->getId();
423-
if (!($definition = $node->getValue()) instanceof Definition || $sourceId === $id || ($edge->isLazy() && ($this->proxyDumper ?? $this->getProxyDumper())->isProxyCandidate($definition)) || $edge->isWeak()) {
423+
if (!$node->getValue() instanceof Definition || $sourceId === $id || $edge->isLazy() || $edge->isWeak()) {
424424
continue;
425425
}
426426

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1374,6 +1374,9 @@ public function testAlmostCircular($visibility)
13741374
$container = include __DIR__.'/Fixtures/containers/container_almost_circular.php';
13751375
$container->compile();
13761376

1377+
$entityManager = $container->get('doctrine.entity_manager');
1378+
$this->assertEquals(new \stdClass(), $entityManager);
1379+
13771380
$pA = $container->get('pA');
13781381
$this->assertEquals(new \stdClass(), $pA);
13791382

src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1054,6 +1054,9 @@ public function testAlmostCircular($visibility)
10541054

10551055
$container = new $container();
10561056

1057+
$entityManager = $container->get('doctrine.entity_manager');
1058+
$this->assertEquals(new \stdClass(), $entityManager);
1059+
10571060
$pA = $container->get('pA');
10581061
$this->assertEquals(new \stdClass(), $pA);
10591062

src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container_almost_circular.php

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<?php
22

3+
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
34
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
45
use Symfony\Component\DependencyInjection\ContainerBuilder;
56
use Symfony\Component\DependencyInjection\Definition;
@@ -9,6 +10,21 @@
910
$public = 'public' === $visibility;
1011
$container = new ContainerBuilder();
1112

13+
// factory with lazy injection
14+
15+
$container->register('doctrine.config', 'stdClass')->setPublic(false)
16+
->setProperty('resolver', new Reference('doctrine.entity_listener_resolver'))
17+
->setProperty('flag', 'ok');
18+
;
19+
20+
$container->register('doctrine.entity_manager', 'stdClass')->setPublic(true)
21+
->setFactory([FactoryChecker::class, 'create'])
22+
->addArgument(new Reference('doctrine.config'));
23+
$container->register('doctrine.entity_listener_resolver', 'stdClass')->setPublic($public)
24+
->addArgument(new IteratorArgument([new Reference('doctrine.listener')]));
25+
$container->register('doctrine.listener', 'stdClass')->setPublic($public)
26+
->addArgument(new Reference('doctrine.entity_manager'));
27+
1228
// multiple path detection
1329

1430
$container->register('pA', 'stdClass')->setPublic(true)
@@ -27,10 +43,13 @@
2743
// monolog-like + handler that require monolog
2844

2945
$container->register('monolog.logger', 'stdClass')->setPublic(true)
30-
->setProperty('handler', new Reference('mailer.transport'));
46+
->setProperty('handler', new Reference('mailer.mailer'));
3147

32-
$container->register('mailer.transport', 'stdClass')->setPublic($public)
33-
->setFactory([new Reference('mailer.transport_factory'), 'create']);
48+
$container->register('mailer.mailer', 'stdClass')->setPublic(false)
49+
->addArgument(
50+
(new Definition('stdClass'))
51+
->setFactory([new Reference('mailer.transport_factory'), 'create'])
52+
);
3453

3554
$container->register('mailer.transport_factory', FactoryCircular::class)->setPublic($public)
3655
->addArgument(new TaggedIteratorArgument('mailer.transport'));
@@ -40,7 +59,7 @@
4059
->addTag('mailer.transport');
4160

4261
$container->register('monolog.logger_2', 'stdClass')->setPublic($public)
43-
->setProperty('handler', new Reference('mailer.transport'));
62+
->setProperty('handler', new Reference('mailer.mailer'));
4463

4564
// same visibility for deps
4665

src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/classes.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,18 @@ public function create()
128128
}
129129
}
130130

131+
class FactoryChecker
132+
{
133+
public static function create($config)
134+
{
135+
if (!isset($config->flag)) {
136+
throw new \LogicException('The injected config must contain a "flag" property.');
137+
}
138+
139+
return new stdClass();
140+
}
141+
}
142+
131143
class FoobarCircular
132144
{
133145
public function __construct(FooCircular $foo)

src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_almost_circular_private.php

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ public function __construct()
2828
'baz6' => 'getBaz6Service',
2929
'connection' => 'getConnectionService',
3030
'connection2' => 'getConnection2Service',
31+
'doctrine.entity_manager' => 'getDoctrine_EntityManagerService',
3132
'foo' => 'getFooService',
3233
'foo2' => 'getFoo2Service',
3334
'foo5' => 'getFoo5Service',
@@ -72,6 +73,9 @@ public function getRemovedIds(): array
7273
'connection4' => true,
7374
'dispatcher' => true,
7475
'dispatcher2' => true,
76+
'doctrine.config' => true,
77+
'doctrine.entity_listener_resolver' => true,
78+
'doctrine.listener' => true,
7579
'foo4' => true,
7680
'foobar' => true,
7781
'foobar2' => true,
@@ -82,7 +86,7 @@ public function getRemovedIds(): array
8286
'level5' => true,
8387
'level6' => true,
8488
'logger2' => true,
85-
'mailer.transport' => true,
89+
'mailer.mailer' => true,
8690
'mailer.transport_factory' => true,
8791
'mailer.transport_factory.amazon' => true,
8892
'manager4' => true,
@@ -185,6 +189,22 @@ protected function getConnection2Service()
185189
return $instance;
186190
}
187191

192+
/**
193+
* Gets the public 'doctrine.entity_manager' shared service.
194+
*
195+
* @return \stdClass
196+
*/
197+
protected function getDoctrine_EntityManagerService()
198+
{
199+
$a = new \stdClass();
200+
$a->resolver = new \stdClass(new RewindableGenerator(function () {
201+
yield 0 => ($this->privates['doctrine.listener'] ?? $this->getDoctrine_ListenerService());
202+
}, 1));
203+
$a->flag = 'ok';
204+
205+
return $this->services['doctrine.entity_manager'] = \FactoryChecker::create($a);
206+
}
207+
188208
/**
189209
* Gets the public 'foo' shared service.
190210
*
@@ -373,7 +393,7 @@ protected function getMonolog_LoggerService()
373393
{
374394
$this->services['monolog.logger'] = $instance = new \stdClass();
375395

376-
$instance->handler = ($this->privates['mailer.transport'] ?? $this->getMailer_TransportService());
396+
$instance->handler = ($this->privates['mailer.mailer'] ?? $this->getMailer_MailerService());
377397

378398
return $instance;
379399
}
@@ -448,6 +468,16 @@ protected function getBar6Service()
448468
return $this->privates['bar6'] = new \stdClass($a);
449469
}
450470

471+
/**
472+
* Gets the private 'doctrine.listener' shared service.
473+
*
474+
* @return \stdClass
475+
*/
476+
protected function getDoctrine_ListenerService()
477+
{
478+
return $this->privates['doctrine.listener'] = new \stdClass(($this->services['doctrine.entity_manager'] ?? $this->getDoctrine_EntityManagerService()));
479+
}
480+
451481
/**
452482
* Gets the private 'level5' shared service.
453483
*
@@ -465,15 +495,15 @@ protected function getLevel5Service()
465495
}
466496

467497
/**
468-
* Gets the private 'mailer.transport' shared service.
498+
* Gets the private 'mailer.mailer' shared service.
469499
*
470500
* @return \stdClass
471501
*/
472-
protected function getMailer_TransportService()
502+
protected function getMailer_MailerService()
473503
{
474-
return $this->privates['mailer.transport'] = (new \FactoryCircular(new RewindableGenerator(function () {
504+
return $this->privates['mailer.mailer'] = new \stdClass((new \FactoryCircular(new RewindableGenerator(function () {
475505
yield 0 => ($this->privates['mailer.transport_factory.amazon'] ?? $this->getMailer_TransportFactory_AmazonService());
476-
}, 1)))->create();
506+
}, 1)))->create());
477507
}
478508

479509
/**
@@ -487,7 +517,7 @@ protected function getMailer_TransportFactory_AmazonService()
487517

488518
$this->privates['mailer.transport_factory.amazon'] = $instance = new \stdClass($a);
489519

490-
$a->handler = ($this->privates['mailer.transport'] ?? $this->getMailer_TransportService());
520+
$a->handler = ($this->privates['mailer.mailer'] ?? $this->getMailer_MailerService());
491521

492522
return $instance;
493523
}

0 commit comments

Comments
 (0)