Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitcaba97a

Browse files
feature#21455 [DI] Allow to count on lazy collection arguments (ogizanagi)
This PR was merged into the 3.3-dev branch.Discussion----------[DI] Allow to count on lazy collection arguments| Q | A| ------------- | ---| Branch? | master| Bug fix? | no| New feature? | yes| BC breaks? | no| Deprecations? | no| Tests pass? | yes| Fixed tickets |#21450 (comment)| License | MIT| Doc PR | todo (withsymfony/symfony-docs#7336)When using the new iterator feature of the DI component to lazy load collection, we always know the number of arguments in the collection (only the invalidBehavior set to `IGNORE_ON_INVALID_REFERENCE` may change this number). So we are able to generate and use a `RewindableGenerator` implementing `\Countable` by computing this value ahead.So, in a service accepting `array|iterable`, like in the `GuardAuthenticationListener` (see#21450):```phpclass GuardAuthenticationListener implements ListenerInterface{ private $guardAuthenticators; /** *@param iterable|GuardAuthenticatorInterface[] $guardAuthenticators The authenticators, with keys that match what's passed to GuardAuthenticationProvider *@param LoggerInterface $logger A LoggerInterface instance */ public function __construct($guardAuthenticators, LoggerInterface $logger = null) { // ... } public function handle(GetResponseEvent $event) { if (null !== $this->logger) { $context = array() if (is_array($this->guardAuthenticators) || $this->guardAuthenticators instanceof \Countable) { $context['authenticators'] = count($this->guardAuthenticators); } $this->logger->debug('Checking for guard authentication credentials.', $context); } // ... }}```we still keep the ability to call count without loosing the lazy load benefits.Commits-------f23e460 [DI] Allow to count on lazy collection arguments
2 parents55a34b7 +f23e460 commitcaba97a

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 RewindableGeneratorimplements \IteratorAggregate
17+
class RewindableGeneratorimplements \IteratorAggregate, \Countable
1818
{
1919
private$generator;
20+
private$count;
2021

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

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

3036
return$g();
3137
}
38+
39+
publicfunctioncount()
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
@@ -1002,6 +1002,19 @@ public function resolveServices($value)
10021002

10031003
yield$k =>$this->resolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($v)));
10041004
}
1005+
},function ()use ($value) {
1006+
$count =0;
1007+
foreach ($value->getValues()as$v) {
1008+
foreach (self::getServiceConditionals($v)as$s) {
1009+
if (!$this->has($s)) {
1010+
continue2;
1011+
}
1012+
}
1013+
1014+
++$count;
1015+
}
1016+
1017+
return$count;
10051018
});
10061019
}elseif ($valueinstanceof ClosureProxyArgument) {
10071020
$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
privatefunctionwrapServiceConditionals($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+
returnsprintf(" 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+
privatefunctiongetServiceConditionals($value,$containerRef ='$this')
1384+
{
1385+
if (!$services = ContainerBuilder::getServiceConditionals($value)) {
1386+
returnnull;
1387+
}
1388+
13691389
$conditions =array();
13701390
foreach ($servicesas$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-
returnsprintf(" if (%s) {\n%s }\n",implode(' &&',$conditions),$code);
1394+
returnimplode(' &&',$conditions);
13781395
}
13791396

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

15251542
returnsprintf('array(%s)',implode(',',$code));
15261543
}elseif ($valueinstanceof 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
returnimplode("\n",$code);
15401566
}elseif ($valueinstanceof 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+
namespaceSymfony\Component\DependencyInjection\Tests\Argument;
13+
14+
useSymfony\Component\DependencyInjection\Argument\RewindableGenerator;
15+
16+
class RewindableGeneratorTestextends \PHPUnit_Framework_TestCase
17+
{
18+
publicfunctiontestImplementsCountable()
19+
{
20+
$this->assertInstanceOf(\Countable::class,newRewindableGenerator(function () {
21+
yield1;
22+
},1));
23+
}
24+
25+
publicfunctiontestCountUsesProvidedValue()
26+
{
27+
$generator =newRewindableGenerator(function () {
28+
yield1;
29+
},3);
30+
31+
$this->assertCount(3,$generator);
32+
}
33+
34+
publicfunctiontestCountUsesProvidedValueAsCallback()
35+
{
36+
$called =0;
37+
$generator =newRewindableGenerator(function () {
38+
yield1;
39+
},function ()use (&$called) {
40+
++$called;
41+
42+
return3;
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
@@ -423,6 +423,7 @@ public function testCreateServiceWithIteratorArgument()
423423

424424
$lazyContext =$builder->get('lazy_context');
425425
$this->assertInstanceOf(RewindableGenerator::class,$lazyContext->lazyValues);
426+
$this->assertCount(1,$lazyContext->lazyValues);
426427

427428
$i =0;
428429
foreach ($lazyContext->lazyValuesas$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
protectedfunctiongetLazyContextService()
316316
{
317-
return$this->services['lazy_context'] =new \LazyContext(newRewindableGenerator(function() {
317+
return$this->services['lazy_context'] =new \LazyContext(newRewindableGenerator(function() {
318318
yield0 =>'foo';
319319
yield1 =>${($_ =isset($this->services['foo.baz']) ?$this->services['foo.baz'] :$this->get('foo.baz')) &&false ?:'_'};
320320
yield2 =>array($this->getParameter('foo') =>'foo is'.$this->getParameter('foo').'','foobar' =>$this->getParameter('foo'));
321321
yield3 =>true;
322322
yield4 =>$this;
323-
}));
323+
},5));
324324
}
325325

326326
/**
@@ -333,11 +333,13 @@ protected function getLazyContextService()
333333
*/
334334
protectedfunctiongetLazyContextIgnoreInvalidRefService()
335335
{
336-
return$this->services['lazy_context_ignore_invalid_ref'] =new \LazyContext(newRewindableGenerator(function() {
336+
return$this->services['lazy_context_ignore_invalid_ref'] =new \LazyContext(newRewindableGenerator(function() {
337337
yield0 =>${($_ =isset($this->services['foo.baz']) ?$this->services['foo.baz'] :$this->get('foo.baz')) &&false ?:'_'};
338338
if ($this->has('invalid')) {
339339
yield1 =>$this->get('invalid', ContainerInterface::NULL_ON_INVALID_REFERENCE);
340340
}
341+
},function () {
342+
return1 + (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
protectedfunctiongetLazyContextService()
315315
{
316-
return$this->services['lazy_context'] =new \LazyContext(newRewindableGenerator(function() {
316+
return$this->services['lazy_context'] =new \LazyContext(newRewindableGenerator(function() {
317317
yield0 =>'foo';
318318
yield1 =>${($_ =isset($this->services['foo.baz']) ?$this->services['foo.baz'] :$this->get('foo.baz')) &&false ?:'_'};
319319
yield2 =>array('bar' =>'foo is bar','foobar' =>'bar');
320320
yield3 =>true;
321321
yield4 =>$this;
322-
}));
322+
},5));
323323
}
324324

325325
/**
@@ -332,9 +332,9 @@ protected function getLazyContextService()
332332
*/
333333
protectedfunctiongetLazyContextIgnoreInvalidRefService()
334334
{
335-
return$this->services['lazy_context_ignore_invalid_ref'] =new \LazyContext(newRewindableGenerator(function() {
335+
return$this->services['lazy_context_ignore_invalid_ref'] =new \LazyContext(newRewindableGenerator(function() {
336336
yield0 =>${($_ =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)

[8]ページ先頭

©2009-2025 Movatter.jp