Adjust cycle implementation

This commit is contained in:
Simon André
2024-08-26 23:10:00 +02:00
committed by Fabien Potencier
parent 7e7808d56e
commit 7c3c16154e
6 changed files with 84 additions and 25 deletions
+6 -4
View File
@@ -1,7 +1,7 @@
``cycle``
=========
The ``cycle`` function cycles on a sequence or mapping:
The ``cycle`` function cycles on a sequence:
.. code-block:: twig
@@ -23,7 +23,9 @@ The ``cycle`` function cycles on a sequence or mapping:
#}
The array can contain any number of values:
The ``cycle`` function takes two arguments: the ``sequence`` to cycle through and the ``position`` in the sequence.
The ``sequence`` must be non-empty and can contain any number of values:
.. code-block:: twig
@@ -52,5 +54,5 @@ The array can contain any number of values:
Arguments
---------
* ``values``: The list of values to cycle on
* ``position``: The cycle position
* ``values``: The sequence to cycle on
* ``position``: The position in the sequence
+23 -10
View File
@@ -330,26 +330,39 @@ final class CoreExtension extends AbstractExtension
}
/**
* Cycles over a value.
* Cycles over a sequence.
*
* @param \ArrayAccess|array $values
* @param int $position The cycle position
* @param array|\ArrayAccess $values A non-empty sequence of values
* @param positive-int $position The position of the value to return in the cycle
*
* @return string The next value in the cycle
* @return mixed The value at the given position in the sequence, wrapping around as needed
*
* @internal
*/
public static function cycle($values, $position): string
public static function cycle($values, $position): mixed
{
if (!\is_array($values) && !$values instanceof \ArrayAccess) {
return $values;
if (!\is_array($values)) {
if (!$values instanceof \ArrayAccess) {
throw new RuntimeError('The "cycle" function expects an array or "ArrayAccess" as first argument.');
}
if (!\is_countable($values)) {
// To be uncommented in 4.0
// throw new RuntimeError('The "cycle" function expects a countable sequence as first argument.');
trigger_deprecation('twig/twig', '3.12', 'Passing a non-countable sequence of values to "%s()" is deprecated.', __METHOD__);
return $values;
}
$values = self::toArray($values, false);
}
if (!\count($values)) {
throw new RuntimeError('The "cycle" function does not work on empty sequences/mappings.');
if (!$count = \count($values)) {
throw new RuntimeError('The "cycle" function does not work on empty sequences.');
}
return $values[$position % \count($values)];
return $values[$position % $count];
}
/**
+40
View File
@@ -17,6 +17,46 @@ use Twig\Extension\CoreExtension;
class CoreTest extends TestCase
{
/**
* @dataProvider provideCycleCases
*/
public function testCycleFunction($values, $position, $expected)
{
$this->assertSame($expected, CoreExtension::cycle($values, $position));
}
public static function provideCycleCases()
{
return [
[[1, 2, 3], 0, 1],
[[1, 2, 3], 1, 2],
[[1, 2, 3], 2, 3],
[[1, 2, 3], 3, 1],
[[false, 0, null], 0, false],
[[false, 0, null], 1, 0],
[[false, 0, null], 2, null],
[[['a', 'b'], ['c', 'd']], 3, ['c', 'd']],
];
}
/**
* @dataProvider provideCycleInvalidCases
*/
public function testCycleFunctionThrowRuntimeError($values, mixed $position = null)
{
$this->expectException(RuntimeError::class);
CoreExtension::cycle($values, $position ?? 0);
}
public static function provideCycleInvalidCases()
{
return [
'empty' => [[]],
'non-countable' => [new class extends \ArrayObject{}],
];
}
/**
* @dataProvider getRandomFunctionTestData
*/
+13 -9
View File
@@ -2,15 +2,19 @@
"cycle" function
--TEMPLATE--
{% for i in 0..6 %}
{{ cycle(array1, i) }}-{{ cycle(array2, i) }}
{{ cycle(array1, i) }}-{{ cycle(array2, i) }}-{{ cycle(array3, i) }}
{% endfor %}
--DATA--
return ['array1' => ['odd', 'even'], 'array2' => ['apple', 'orange', 'citrus']]
return [
'array1' => ['odd', 'even'],
'array2' => ['apple', 'orange', 'citrus'],
'array3' => [1, 2, false, null],
];
--EXPECT--
odd-apple
even-orange
odd-citrus
even-apple
odd-orange
even-citrus
odd-apple
odd-apple-1
even-orange-2
odd-citrus-
even-apple-
odd-orange-1
even-citrus-2
odd-apple-
@@ -5,4 +5,4 @@
--DATA--
return []
--EXCEPTION--
Twig\Error\RuntimeError: The "cycle" function does not work on empty sequences/mappings in "index.twig" at line 2.
Twig\Error\RuntimeError: The "cycle" function does not work on empty sequences in "index.twig" at line 2.
@@ -5,4 +5,4 @@
--DATA--
return []
--EXCEPTION--
Twig\Error\RuntimeError: The "cycle" function does not work on empty sequences/mappings in "index.twig" at line 2.
Twig\Error\RuntimeError: The "cycle" function does not work on empty sequences in "index.twig" at line 2.