mirror of
https://github.com/twigphp/Twig.git
synced 2026-08-26 09:36:40 +00:00
Adjust cycle implementation
This commit is contained in:
committed by
Fabien Potencier
parent
7e7808d56e
commit
7c3c16154e
@@ -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
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user