8000 [DI] Allow to count on lazy collection arguments · symfony/symfony@a74819e · GitHub
[go: up one dir, main page]

Skip to content

Commit a74819e

Browse files
committed
[DI] Allow to count on lazy collection arguments
1 parent bcf8b68 commit a74819e

File tree

6 files changed

+121
-14
lines changed

6 files changed

+121
-14
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 & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -966,6 +966,18 @@ public function resolveServices($value)
966966
}
967967
} elseif ($value instanceof IteratorArgument) {
968968
$parameterBag = $this->getParameterBag();
969+
970+
$count = 0;
971+
foreach ($value->getValues() as $k => $v) {
972+
foreach (self::getServiceConditionals($v) as $s) {
973+
if (!$this->has($s)) {
974+
continue 2;
975+
}
976+
}
977+
978+
++$count;
979+
}
980+
969981
$value = new RewindableGenerator(function () use ($value, $parameterBag) {
970982
foreach ($value->getValues() as $k => $v) {
971983
foreach (self::getServiceConditionals($v) as $s) {
@@ -976,7 +988,7 @@ public function resolveServices($value)
976988

977989
yield $k => $this->resolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($v)));
978990
}
979-
});
991+
}, $count);
980992
} elseif ($value instanceof ClosureProxyArgument) {
981993
$parameterBag = $this->getParameterBag();
982994
list($reference, $method) = $value->getValues();

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

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1226,19 +1226,35 @@ private function endClass()
12261226
*/
12271227
private function wrapServiceConditionals($value, $code)
12281228
{
1229-
if (!$services = ContainerBuilder::getServiceConditionals($value)) {
1229+
if (null === $condition = $this->getServiceConditionals($value)) {
12301230
return $code;
12311231
}
12321232

1233+
// re-indent the wrapped code
1234+
$code = implode("\n", array_map(function ($line) { return $line ? ' '.$line : $line; }, explode("\n", $code)));
1235+
1236+
return sprintf(" if (%s) {\n%s }\n", $condition, $code);
1237+
}
1238+
1239+
/**
1240+
* Get the conditions to execute for conditional services.
1241+
*
1242+
* @param string $value
1243+
*
1244+
* @return string|null
1245+
*/
1246+
private function getServiceConditionals($value)
1247+
{
1248+
if (!$services = ContainerBuilder::getServiceConditionals($value)) {
1249+
return null;
1250+
}
1251+
12331252
$conditions = array();
12341253
foreach ($services as $service) {
12351254
$conditions[] = sprintf("\$this->has('%s')", $service);
12361255
}
12371256

1238-
// re-indent the wrapped code
1239-
$code = implode("\n", array_map(function ($line) { return $line ? ' '.$line : $line; }, explode("\n", $code)));
1240-
1241-
return sprintf(" if (%s) {\n%s }\n", implode(' && ', $conditions), $code);
1257+
return sprintf('%s', implode(' && ', $conditions));
12421258
}
12431259

12441260
/**
@@ -1387,17 +1403,27 @@ private function dumpValue($value, $interpolate = true)
13871403

13881404
return sprintf('array(%s)', implode(', ', $code));
13891405
} elseif ($value instanceof IteratorArgument) {
1406+
$countCode = array();
1407+
$countCode[] = 'function() {';
1408+
$operands = array(0);
1409+
13901410
$code = array();
13911411
$code[] = 'new RewindableGenerator(function() {';
1392-
foreach ($value->getValues() as $k => $v) {
1393-
$v = $this->wrapServiceConditionals($v, sprintf(" yield %s => %s;\n", $this->dumpValue($k, $interpolate), $this->dumpValue($v, $interpolate)));
1412+
foreach ($value->getValues() as $k => $value) {
1413+
$v = $this->wrapServiceConditionals($value, sprintf(" yield %s => %s;\n", $this->dumpValue($k, $interpolate), $this->dumpValue($value, $interpolate)));
13941414
foreach (explode("\n", $v) as $v) {
13951415
if ($v) {
13961416
$code[] = ' '.$v;
13971417
}
13981418
}
1419+
1420+
($c = $this->getServiceConditionals($value)) ? $operands[] = "(int) ($c)" : ++$operands[0];
13991421
}
1400-
$code[] = ' })';
1422+
1423+
$countCode[] = sprintf(' return %s;', implode(' + ', $operands));
1424+
$countCode[] = ' }';
1425+
1426+
$code[] = sprintf(' }, %s)', count($operands) > 1 ? implode("\n", $countCode) : $operands[0]);
14011427

14021428
return implode("\n", $code);
14031429
} elseif ($va 10000 lue 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 <fabien@symfony.com>
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/Fixtures/php/services9.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ protected function getLazyContextService()
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
/**
@@ -338,6 +338,8 @@ protected function getLazyContextIgnoreInvalidRefService()
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: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ protected function getLazyContextService()
319319
yield 2 => array('bar' => 'foo is bar', 'foobar' => 'bar');
320320
yield 3 => true;
321321
yield 4 => $this;
322-
}));
322+
}, 5));
323323
}
324324

325325
/**
@@ -334,7 +334,7 @@ protected function getLazyContextIgnoreInvalidRefService()
334334
{
335335
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)
0