From 0c2a69ceb3a141b0ba5cab70e9f5437f8c95ca57 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Thu, 11 Jul 2024 08:41:17 +0200 Subject: [PATCH] Simplify Loop code --- src/Runtime/Loop.php | 48 ++++++----------------- tests/Fixtures/tags/for/loop_context.test | 14 ++++--- 2 files changed, 21 insertions(+), 41 deletions(-) diff --git a/src/Runtime/Loop.php b/src/Runtime/Loop.php index ab25bc841..46a07e624 100644 --- a/src/Runtime/Loop.php +++ b/src/Runtime/Loop.php @@ -23,11 +23,7 @@ use Twig\Error\RuntimeError; final class Loop implements \Iterator { private \Iterator $seq; - private bool $iterated; private int $index0; - private int $revindex0; - private bool $first; - private bool $last; private int $length; public function __construct($seq, private $parent) @@ -49,29 +45,13 @@ final class Loop implements \Iterator public function next(): void { $this->seq->next(); - - $this->iterated = true; ++$this->index0; - $this->first = false; - if (isset($this->length)) { - --$this->revindex0; - $this->last = 0 === $this->revindex0; - } } public function rewind(): void { $this->seq->rewind(); - - $this->iterated = false; $this->index0 = 0; - $this->first = true; - if ($this->seq instanceof \Countable) { - $length = count($this->seq); - $this->revindex0 = $length - 1; - $this->length = $length; - $this->last = 1 === $length; - } } public function valid(): bool @@ -81,7 +61,7 @@ final class Loop implements \Iterator public function iterated(): bool { - return $this->iterated; + return 0 !== $this->index0; } public function getParent(): mixed @@ -91,11 +71,7 @@ final class Loop implements \Iterator public function getRevindex0(): int { - if (!$this->seq instanceof \Countable) { - throw new RuntimeError('The "loop.revindex0" variable is not defined as the loop iterates on a non-countable iterator.'); - } - - return $this->revindex0; + return $this->getLength('revindex0') - $this->index0 - 1; } public function getIndex0(): int @@ -103,26 +79,26 @@ final class Loop implements \Iterator return $this->index0; } - public function getLength(): int + public function getLength($var = 'length'): int { - if (!$this->seq instanceof \Countable) { - throw new RuntimeError('The "loop.length" variable is not defined as the loop iterates on a non-countable iterator.'); + if (isset($this->length)) { + return $this->length; } - return $this->length; + if (!$this->seq instanceof \Countable) { + throw new RuntimeError(sprintf('The "loop.%s" variable is not defined as the loop iterates on a non-countable iterator.', $var)); + } + + return $this->length = count($this->seq); } public function isFirst(): bool { - return $this->first; + return 0 === $this->index0; } public function isLast(): bool { - if (!$this->seq instanceof \Countable) { - throw new RuntimeError('The "loop.last" variable is not defined as the loop iterates on a non-countable iterator.'); - } - - return $this->last; + return 0 === $this->getLength('last') - $this->index0 - 1; } } diff --git a/tests/Fixtures/tags/for/loop_context.test b/tests/Fixtures/tags/for/loop_context.test index 56a60c2e6..2f5596189 100644 --- a/tests/Fixtures/tags/for/loop_context.test +++ b/tests/Fixtures/tags/for/loop_context.test @@ -4,16 +4,20 @@ {% for item in items %} * {{ loop.index }}/{{ loop.index0 }} * {{ loop.revindex }}/{{ loop.revindex0 }} - * {{ loop.first }}/{{ loop.last }}/{{ loop.length }} + * {{ loop.first ? 'FIRST' : '-' }}/{{ loop.last ? 'LAST' : '-' }}/{{ loop.length }} {% endfor %} --DATA-- -return ['items' => ['a', 'b']] +return ['items' => ['a', 'b', 'c']] --EXPECT-- * 1/0 - * 2/1 - * 1//2 + * 3/2 + * FIRST/-/3 * 2/1 + * 2/1 + * -/-/3 + + * 3/2 * 1/0 - * /1/2 + * -/LAST/3