Skip to content

Commit 473653d

Browse files
committed
[Core] Fix cycle() with non-countable ArrayAccess+Traversable objects
1 parent 2b7cc0b commit 473653d

File tree

2 files changed

+42
-3
lines changed

2 files changed

+42
-3
lines changed

src/Extension/CoreExtension.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -417,10 +417,8 @@ public static function cycle($values, $position): mixed
417417

418418
trigger_deprecation('twig/twig', '3.12', 'Passing a non-countable sequence of values to "%s()" is deprecated.', __METHOD__);
419419

420-
return $values;
420+
$values = self::toArray($values, false);
421421
}
422-
423-
$values = self::toArray($values, false);
424422
}
425423

426424
if (!$count = \count($values)) {

tests/Extension/CoreTest.php

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
*/
2222

2323
use PHPUnit\Framework\TestCase;
24+
use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
2425
use Twig\Environment;
2526
use Twig\Error\RuntimeError;
2627
use Twig\Extension\CoreExtension;
@@ -31,6 +32,8 @@
3132

3233
class CoreTest extends TestCase
3334
{
35+
use ExpectDeprecationTrait;
36+
3437
/**
3538
* @dataProvider provideCycleCases
3639
*/
@@ -407,6 +410,44 @@ public function testLastModified()
407410
{
408411
$this->assertGreaterThan(1000000000, (new CoreExtension())->getLastModified());
409412
}
413+
414+
/**
415+
* @group legacy
416+
*/
417+
public function testCycleWithArrayAccessAndTraversableButNotCountable()
418+
{
419+
$this->expectDeprecation('Since twig/twig 3.12: Passing a non-countable sequence of values to "Twig\Extension\CoreExtension::cycle()" is deprecated.');
420+
421+
$seq = new class implements \ArrayAccess, \IteratorAggregate {
422+
public function offsetExists($offset): bool
423+
{
424+
return true;
425+
}
426+
427+
public function offsetGet($offset): mixed
428+
{
429+
return 'val';
430+
}
431+
432+
public function offsetSet($offset, $value): void
433+
{
434+
}
435+
436+
public function offsetUnset($offset): void
437+
{
438+
}
439+
440+
public function getIterator(): \Traversable
441+
{
442+
yield 'odd';
443+
yield 'even';
444+
}
445+
};
446+
447+
$result = CoreExtension::cycle($seq, 0);
448+
449+
$this->assertEquals('odd', $result, 'cycle should return the first item from the traversable sequence, not the sequence itself.');
450+
}
410451
}
411452

412453
final class CoreTestIteratorAggregate implements \IteratorAggregate

0 commit comments

Comments
 (0)