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

Skip to content

Commit f23e460

Browse files
committed
[DI] Allow to count on lazy collection arguments
1 parent 2183f98 commit f23e460

File tree

7 files changed

+125
-16
lines changed

7 files changed

+125
-16
lines changed

src/Symfony/Component/DependencyInjection/Argument/RewindableGenerator.php

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,19 @@
1414
/**
1515
* @internal
1616
*/
17-
class RewindableGenerator implements \IteratorAggregate
17+
class RewindableGenerator implements \IteratorAggregate, \Countable
1818
{
1919
private $generator;
20+
private $count;
2021

21-
public function __construct(callable $generator)
22+
/**
23+
* @param callable $generator
24+
* @param int|callable $count
25+
*/
26+
public function __construct(callable $generator, $count)
2227
{
2328
$this->generator = $generator;
29+
$this->count = $count;
2430
}
2531

2632
public function getIterator()
@@ -29,4 +35,13 @@ public function getIterator()
2935

3036
return $g();
3137
}
38+
39+
public function count()
40+
{
41+
if (is_callable($count = $this->count)) {
42+
$this->count = $count();
43+
}
44+
45+
return $this->count;
46+
}
3247
}

src/Symfony/Component/DependencyInjection/ContainerBuilder.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1000,6 +1000,19 @@ public function resolveServices($value)
10001000

10011001
yield $k => $this->resolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($v)));
10021002
}
1003+
}, function () use ($value) {
1004+
$count = 0;
1005+
foreach ($value->getValues() as $v) {
1006+
foreach (self::getServiceConditionals($v) as $s) {
1007+
if (!$this->has($s)) {
1008+
continue 2;
1009+
}
1010+
}
1011+
1012+
++$count;
1013+
}
1014+
1015+
return $count;
10031016
});
10041017
} elseif ($value instanceof ClosureProxyArgument) {
10051018
$parameterBag = $this->getParameterBag();

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

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1362,19 +1362,36 @@ private function instantiateProxy($class, $args, $useConstructor)
13621362
*/
13631363
private function wrapServiceConditionals($value, $code, &$isUnconditional = null, $containerRef = '$this')
13641364
{
1365-
if ($isUnconditional = !$services = ContainerBuilder::getServiceConditionals($value)) {
1365+
if ($isUnconditional = !$condition = $this->getServiceConditionals($value, $containerRef)) {
13661366
return $code;
13671367
}
13681368

1369+
// re-indent the wrapped code
1370+
$code = implode("\n", array_map(function ($line) { return $line ? ' '.$line : $line; }, explode("\n", $code)));
1371+
1372+
return sprintf(" if (%s) {\n%s }\n", $condition, $code);
1373+
}
1374+
1375+
/**
1376+
* Get the conditions to execute for conditional services.
1377+
*
1378+
* @param string $value
1379+
* @param string $containerRef
1380+
*
1381+
* @return null|string
1382+
*/
1383+
private function getServiceConditionals($value, $containerRef = '$this')
1384+
{
1385+
if (!$services = ContainerBuilder::getServiceConditionals($value)) {
1386+
return null;
1387+
}
1388+
13691389
$conditions = array();
13701390
foreach ($services as $service) {
13711391
$conditions[] = sprintf("%s->has('%s')", $containerRef, $service);
13721392
}
13731393

1374-
// re-indent the wrapped code
1375-
$code = implode("\n", array_map(function ($line) { return $line ? ' '.$line : $line; }, explode("\n", $code)));
1376-
1377-
return sprintf(" if (%s) {\n%s }\n", implode(' && ', $conditions), $code);
1394+
return implode(' && ', $conditions);
13781395
}
13791396

13801397
/**
@@ -1524,17 +1541,26 @@ private function dumpValue($value, $interpolate = true)
15241541

15251542
return sprintf('array(%s)', implode(', ', $code));
15261543
} elseif ($value instanceof IteratorArgument) {
1544+
$countCode = array();
1545+
$countCode[] = 'function () {';
1546+
$operands = array(0);
1547+
15271548
$code = array();
1528-
$code[] = 'new RewindableGenerator(function() {';
1549+
$code[] = 'new RewindableGenerator(function () {';
15291550
foreach ($value->getValues() as $k => $v) {
1551+
($c = $this->getServiceConditionals($v)) ? $operands[] = "(int) ($c)" : ++$operands[0];
15301552
$v = $this->wrapServiceConditionals($v, sprintf(" yield %s => %s;\n", $this->dumpValue($k, $interpolate), $this->dumpValue($v, $interpolate)));
15311553
foreach (explode("\n", $v) as $v) {
15321554
if ($v) {
15331555
$code[] = ' '.$v;
15341556
}
15351557
}
15361558
}
1537-
$code[] = ' })';
1559+
1560+
$countCode[] = sprintf(' return %s;', implode(' + ', $operands));
1561+
$countCode[] = ' }';
1562+
1563+
$code[] = sprintf(' }, %s)', count($operands) > 1 ? implode("\n", $countCode) : $operands[0]);
15381564

15391565
return implode("\n", $code);
15401566
} elseif ($value instanceof Definition) {
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\DependencyInjection\Tests\Argument;
13+
14+
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
15+
16+
class RewindableGeneratorTest extends \PHPUnit_Framework_TestCase
17+
{
18+
public function testImplementsCountable()
19+
{
20+
$this->assertInstanceOf(\Countable::class, new RewindableGenerator(function () {
21+
yield 1;
22+
}, 1));
23+
}
24+
25+
public function testCountUsesProvidedValue()
26+
{
27+
$generator = new RewindableGenerator(function () {
28+
yield 1;
29+
}, 3);
30+
31+
$this->assertCount(3, $generator);
32+
}
33+
34+
public function testCountUsesProvidedValueAsCallback()
35+
{
36+
$called = 0;
37+
$generator = new RewindableGenerator(function () {
38+
yield 1;
39+
}, function () use (&$called) {
40+
++$called;
41+
42+
return 3;
43+
});
44+
45+
$this->assertSame(0, $called, 'Count callback is called lazily');
46+
$this->assertCount(3, $generator);
47+
48+
count($generator);
49+
50+
$this->assertSame(1, $called, 'Count callback is called only once');
51+
}
52+
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,7 @@ public function testCreateServiceWithIteratorArgument()
422422

423423
$lazyContext = $builder->get('lazy_context');
424424
$this->assertInstanceOf(RewindableGenerator::class, $lazyContext->lazyValues);
425+
$this->assertCount(1, $lazyContext->lazyValues);
425426

426427
$i = 0;
427428
foreach ($lazyContext->lazyValues as $k => $v) {

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -314,13 +314,13 @@ protected function getFooWithInlineService()
314314
*/
315315
protected function getLazyContextService()
316316
{
317-
return $this->services['lazy_context'] = new \LazyContext(new RewindableGenerator(function() {
317+
return $this->services['lazy_context'] = new \LazyContext(new RewindableGenerator(function () {
318318
yield 0 => 'foo';
319319
yield 1 => ${($_ = isset($this->services['foo.baz']) ? $this->services['foo.baz'] : $this->get('foo.baz')) && false ?: '_'};
320320
yield 2 => array($this->getParameter('foo') => 'foo is '.$this->getParameter('foo').'', 'foobar' => $this->getParameter('foo'));
321321
yield 3 => true;
322322
yield 4 => $this;
323-
}));
323+
}, 5));
324324
}
325325

326326
/**
@@ -333,11 +333,13 @@ protected function getLazyContextService()
333333
*/
334334
protected function getLazyContextIgnoreInvalidRefService()
335335
{
336-
return $this->services['lazy_context_ignore_invalid_ref'] = new \LazyContext(new RewindableGenerator(function() {
336+
return $this->services['lazy_context_ignore_invalid_ref'] = new \LazyContext(new RewindableGenerator(function () {
337337
yield 0 => ${($_ = isset($this->services['foo.baz']) ? $this->services['foo.baz'] : $this->get('foo.baz')) && false ?: '_'};
338338
if ($this->has('invalid')) {
339339
yield 1 => $this->get('invalid', ContainerInterface::NULL_ON_INVALID_REFERENCE);
340340
}
341+
}, function () {
342+
return 1 + (int) ($this->has('invalid'));
341343
}));
342344
}
343345

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -313,13 +313,13 @@ protected function getFooWithInlineService()
313313
*/
314314
protected function getLazyContextService()
315315
{
316-
return $this->services['lazy_context'] = new \LazyContext(new RewindableGenerator(function() {
316+
return $this->services['lazy_context'] = new \LazyContext(new RewindableGenerator(function () {
317317
yield 0 => 'foo';
318318
yield 1 => ${($_ = isset($this->services['foo.baz']) ? $this->services['foo.baz'] : $this->get('foo.baz')) && false ?: '_'};
319319
yield 2 => array('bar' => 'foo is bar', 'foobar' => 'bar');
320320
yield 3 => true;
321321
yield 4 => $this;
322-
}));
322+
}, 5));
323323
}
324324

325325
/**
@@ -332,9 +332,9 @@ protected function getLazyContextService()
332332
*/
333333
protected function getLazyContextIgnoreInvalidRefService()
334334
{
335-
return $this->services['lazy_context_ignore_invalid_ref'] = new \LazyContext(new RewindableGenerator(function() {
335+
return $this->services['lazy_context_ignore_invalid_ref'] = new \LazyContext(new RewindableGenerator(function () {
336336
yield 0 => ${($_ = isset($this->services['foo.baz']) ? $this->services['foo.baz'] : $this->get('foo.baz')) && false ?: '_'};
337-
}));
337+
}, 1));
338338
}
339339

340340
/**

0 commit comments

Comments
 (0)