Skip to content

Commit 88abc79

Browse files
committed
Fix circular referene with Factory and LazyIterator
1 parent 6883d61 commit 88abc79

File tree

8 files changed

+171
-4
lines changed

8 files changed

+171
-4
lines changed

ContainerBuilder.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1220,20 +1220,20 @@ private function doResolveServices($value, array &$inlineServices = [], bool $is
12201220
return $this->resolveServices($reference);
12211221
};
12221222
} elseif ($value instanceof IteratorArgument) {
1223-
$value = new RewindableGenerator(function () use ($value) {
1223+
$value = new RewindableGenerator(function () use ($value, &$inlineServices) {
12241224
foreach ($value->getValues() as $k => $v) {
12251225
foreach (self::getServiceConditionals($v) as $s) {
12261226
if (!$this->has($s)) {
12271227
continue 2;
12281228
}
12291229
}
12301230
foreach (self::getInitializedConditionals($v) as $s) {
1231-
if (!$this->doGet($s, ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE)) {
1231+
if (!$this->doGet($s, ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE, $inlineServices)) {
12321232
continue 2;
12331233
}
12341234
}
12351235

1236-
yield $k => $this->resolveServices($v);
1236+
yield $k => $this->doResolveServices($v, $inlineServices);
12371237
}
12381238
}, function () use ($value): int {
12391239
$count = 0;

Dumper/PhpDumper.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,7 @@ private function collectCircularReferences(string $sourceId, array $edges, array
451451
foreach ($edges as $edge) {
452452
$node = $edge->getDestNode();
453453
$id = $node->getId();
454-
if (!$node->getValue() instanceof Definition || $sourceId === $id || $edge->isLazy() || $edge->isWeak()) {
454+
if (!$node->getValue() instanceof Definition || $sourceId === $id || $edge->isWeak()) {
455455
continue;
456456
}
457457

Tests/ContainerBuilderTest.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1372,6 +1372,10 @@ public function testUninitializedReference()
13721372
public function testAlmostCircular($visibility)
13731373
{
13741374
$container = include __DIR__.'/Fixtures/containers/container_almost_circular.php';
1375+
$container->compile();
1376+
1377+
$logger = $container->get('monolog.logger');
1378+
$this->assertEquals(new \stdClass(), $logger->handler);
13751379

13761380
$foo = $container->get('foo');
13771381
$this->assertSame($foo, $foo->bar->foobar->foo);

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+
$logger = $container->get('monolog.logger');
1058+
$this->assertEquals(new \stdClass(), $logger->handler);
1059+
10571060
$foo = $container->get('foo');
10581061
$this->assertSame($foo, $foo->bar->foobar->foo);
10591062

Tests/Fixtures/containers/container_almost_circular.php

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

3+
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
34
use Symfony\Component\DependencyInjection\ContainerBuilder;
45
use Symfony\Component\DependencyInjection\Definition;
56
use Symfony\Component\DependencyInjection\Reference;
@@ -8,6 +9,24 @@
89
$public = 'public' === $visibility;
910
$container = new ContainerBuilder();
1011

12+
// monolog-like + handler that require monolog
13+
14+
$container->register('monolog.logger', 'stdClass')->setPublic(true)
15+
->setProperty('handler', new Reference('mailer.transport'));
16+
17+
$container->register('mailer.transport', 'stdClass')->setPublic($public)
18+
->setFactory([new Reference('mailer.transport_factory'), 'create']);
19+
20+
$container->register('mailer.transport_factory', FactoryCircular::class)->setPublic($public)
21+
->addArgument(new TaggedIteratorArgument('mailer.transport'));
22+
23+
$container->register('mailer.transport_factory.amazon', 'stdClass')->setPublic($public)
24+
->addArgument(new Reference('monolog.logger_2'))
25+
->addTag('mailer.transport');
26+
27+
$container->register('monolog.logger_2', 'stdClass')->setPublic($public)
28+
->setProperty('handler', new Reference('mailer.transport'));
29+
1130
// same visibility for deps
1231

1332
$container->register('foo', FooCircular::class)->setPublic(true)

Tests/Fixtures/includes/classes.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,23 @@ public function __construct($lazyValues, $lazyEmptyValues)
111111
}
112112
}
113113

114+
class FactoryCircular
115+
{
116+
public $services;
117+
118+
public function __construct($services)
119+
{
120+
$this->services = $services;
121+
}
122+
123+
public function create()
124+
{
125+
foreach ($this->services as $service) {
126+
return $service;
127+
}
128+
}
129+
}
130+
114131
class FoobarCircular
115132
{
116133
public function __construct(FooCircular $foo)

Tests/Fixtures/php/services_almost_circular_private.php

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ public function __construct()
3939
'manager' => 'getManagerService',
4040
'manager2' => 'getManager2Service',
4141
'manager3' => 'getManager3Service',
42+
'monolog.logger' => 'getMonolog_LoggerService',
4243
'root' => 'getRootService',
4344
'subscriber' => 'getSubscriberService',
4445
];
@@ -80,7 +81,11 @@ public function getRemovedIds(): array
8081
'level5' => true,
8182
'level6' => true,
8283
'logger2' => true,
84+
'mailer.transport' => true,
85+
'mailer.transport_factory' => true,
86+
'mailer.transport_factory.amazon' => true,
8387
'manager4' => true,
88+
'monolog.logger_2' => true,
8489
'multiuse1' => true,
8590
'subscriber2' => true,
8691
];
@@ -355,6 +360,20 @@ protected function getManager3Service($lazyLoad = true)
355360
return $this->services['manager3'] = new \stdClass($b);
356361
}
357362

363+
/**
364+
* Gets the public 'monolog.logger' shared service.
365+
*
366+
* @return \stdClass
367+
*/
368+
protected function getMonolog_LoggerService()
369+
{
370+
$this->services['monolog.logger'] = $instance = new \stdClass();
371+
372+
$instance->handler = ($this->privates['mailer.transport'] ?? $this->getMailer_TransportService());
373+
374+
return $instance;
375+
}
376+
358377
/**
359378
* Gets the public 'root' shared service.
360379
*
@@ -419,6 +438,34 @@ protected function getLevel5Service()
419438
return $instance;
420439
}
421440

441+
/**
442+
* Gets the private 'mailer.transport' shared service.
443+
*
444+
* @return \stdClass
445+
*/
446+
protected function getMailer_TransportService()
447+
{
448+
return $this->privates['mailer.transport'] = (new \FactoryCircular(new RewindableGenerator(function () {
449+
yield 0 => ($this->privates['mailer.transport_factory.amazon'] ?? $this->getMailer_TransportFactory_AmazonService());
450+
}, 1)))->create();
451+
}
452+
453+
/**
454+
* Gets the private 'mailer.transport_factory.amazon' shared service.
455+
*
456+
* @return \stdClass
457+
*/
458+
protected function getMailer_TransportFactory_AmazonService()
459+
{
460+
$a = new \stdClass();
461+
462+
$this->privates['mailer.transport_factory.amazon'] = $instance = new \stdClass($a);
463+
464+
$a->handler = ($this->privates['mailer.transport'] ?? $this->getMailer_TransportService());
465+
466+
return $instance;
467+
}
468+
422469
/**
423470
* Gets the private 'manager4' shared service.
424471
*

Tests/Fixtures/php/services_almost_circular_public.php

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,14 @@ public function __construct()
4545
'listener3' => 'getListener3Service',
4646
'listener4' => 'getListener4Service',
4747
'logger' => 'getLoggerService',
48+
'mailer.transport' => 'getMailer_TransportService',
49+
'mailer.transport_factory' => 'getMailer_TransportFactoryService',
50+
'mailer.transport_factory.amazon' => 'getMailer_TransportFactory_AmazonService',
4851
'manager' => 'getManagerService',
4952
'manager2' => 'getManager2Service',
5053
'manager3' => 'getManager3Service',
54+
'monolog.logger' => 'getMonolog_LoggerService',
55+
'monolog.logger_2' => 'getMonolog_Logger2Service',
5156
'root' => 'getRootService',
5257
'subscriber' => 'getSubscriberService',
5358
];
@@ -433,6 +438,50 @@ protected function getLoggerService()
433438
return $instance;
434439
}
435440

441+
/**
442+
* Gets the public 'mailer.transport' shared service.
443+
*
444+
* @return \stdClass
445+
*/
446+
protected function getMailer_TransportService()
447+
{
448+
$a = ($this->services['mailer.transport_factory'] ?? $this->getMailer_TransportFactoryService());
449+
450+
if (isset($this->services['mailer.transport'])) {
451+
return $this->services['mailer.transport'];
452+
}
453+
454+
return $this->services['mailer.transport'] = $a->create();
455+
}
456+
457+
/**
458+
* Gets the public 'mailer.transport_factory' shared service.
459+
*
460+
* @return \FactoryCircular
461+
*/
462+
protected function getMailer_TransportFactoryService()
463+
{
464+
return $this->services['mailer.transport_factory'] = new \FactoryCircular(new RewindableGenerator(function () {
465+
yield 0 => ($this->services['mailer.transport_factory.amazon'] ?? $this->getMailer_TransportFactory_AmazonService());
466+
}, 1));
467+
}
468+
469+
/**
470+
* Gets the public 'mailer.transport_factory.amazon' shared service.
471+
*
472+
* @return \stdClass
473+
*/
474+
protected function getMailer_TransportFactory_AmazonService()
475+
{
476+
$a = ($this->services['monolog.logger_2'] ?? $this->getMonolog_Logger2Service());
477+
478+
if (isset($this->services['mailer.transport_factory.amazon'])) {
479+
return $this->services['mailer.transport_factory.amazon'];
480+
}
481+
482+
return $this->services['mailer.transport_factory.amazon'] = new \stdClass($a);
483+
}
484+
436485
/**
437486
* Gets the public 'manager' shared service.
438487
*
@@ -481,6 +530,34 @@ protected function getManager3Service($lazyLoad = true)
481530
return $this->services['manager3'] = new \stdClass($a);
482531
}
483532

533+
/**
534+
* Gets the public 'monolog.logger' shared service.
535+
*
536+
* @return \stdClass
537+
*/
538+
protected function getMonolog_LoggerService()
539+
{
540+
$this->services['monolog.logger'] = $instance = new \stdClass();
541+
542+
$instance->handler = ($this->services['mailer.transport'] ?? $this->getMailer_TransportService());
543+
544+
return $instance;
545+
}
546+
547+
/**
548+
* Gets the public 'monolog.logger_2' shared service.
549+
*
550+
* @return \stdClass
551+
*/
552+
protected function getMonolog_Logger2Service()
553+
{
554+
$this->services['monolog.logger_2'] = $instance = new \stdClass();
555+
556+
$instance->handler = ($this->services['mailer.transport'] ?? $this->getMailer_TransportService());
557+
558+
return $instance;
559+
}
560+
484561
/**
485562
* Gets the public 'root' shared service.
486563
*

0 commit comments

Comments
 (0)