Skip to content

Commit

Permalink
[templates] add shuffle filter
Browse files Browse the repository at this point in the history
  • Loading branch information
Sarah-eit committed Jan 19, 2024
1 parent 4c179c8 commit 3e94978
Show file tree
Hide file tree
Showing 7 changed files with 147 additions and 0 deletions.
76 changes: 76 additions & 0 deletions doc/filters/shuffle.rst
@@ -0,0 +1,76 @@
``shuffle``
========

The ``shuffle`` filter shuffles an array:

.. code-block:: twig
{% for user in users|shuffle %}
...
{% endfor %}
.. caution::

Internally, Twig uses the PHP `shuffle`_ function.
This function assigns new keys to the elements in array. It will remove
any existing keys that may have been assigned, rather than just reordering the keys.

Example 1:

.. code-block:: html+twig

{% set items = [
'a',
'b',
'c'
] %}

<ul>
{% for item in items|shuffle %}
<li>{{ item }}</li>
{% endfor %}
</ul>

The above example will be rendered as:

.. code-block:: html+twig

<ul>
<li>a</li>
<li>c</li>
<li>b</li>
</ul>

Note, results can also be :
"a, b, c" or "b, a, c" or "b, c, a" or "c, a, b" or "c, b, a".

Example 2:

.. code-block:: html+twig

{% set items = [
'a' => 'd',
'b' => 'e',
'c' => 'f'
] %}

<ul>
{% for index, item in items|shuffle %}
<li>{{ index }} - {{ item }}</li>
{% endfor %}
</ul>

The above example will be rendered as:

.. code-block:: html+twig

<ul>
<li>0 - d</li>
<li>1 - f</li>
<li>2 - e</li>
</ul>

Note, results can also be :
"d, e, f" or "e, d, f" or "e, f, d" or "f, d, e" or "f, e, d".

.. _`shuffle`: https://www.php.net/shuffle
23 changes: 23 additions & 0 deletions src/Extension/CoreExtension.php
Expand Up @@ -213,6 +213,7 @@ public function getFilters(): array
new TwigFilter('join', [self::class, 'joinFilter']),
new TwigFilter('split', [self::class, 'splitFilter'], ['needs_environment' => true]),
new TwigFilter('sort', [self::class, 'sortFilter'], ['needs_environment' => true]),
new TwigFilter('shuffle', [self::class, 'arrayShuffle']),
new TwigFilter('merge', [self::class, 'arrayMerge']),
new TwigFilter('batch', [self::class, 'arrayBatch']),
new TwigFilter('column', [self::class, 'arrayColumn']),
Expand Down Expand Up @@ -948,6 +949,28 @@ public static function sortFilter(Environment $env, $array, $arrow = null)
return $array;
}

/**
* Shuffle an array.
* The function does not preserve keys.
*
* @param array|\Traversable $array
*
* @return array
*
* @internal
*/
public function shuffle($array)
{
if (!is_iterable($array)) {
throw new RuntimeError(sprintf('The shuffle filter only works with array or "Traversable", got "%s" as argument.', \gettype($array)));
}

$array = self::toArray($array, false);
shuffle($array);

return $array;
}

/**
* @internal
*/
Expand Down
14 changes: 14 additions & 0 deletions tests/Fixtures/filters/shuffle.test
@@ -0,0 +1,14 @@
--TEST--
"shuffle" filter
--TEMPLATE--
{{ array1|shuffle|length }}
{{ array2|shuffle|length }}
{{ array3|shuffle|length }}
{{ traversable|shuffle|length }}
--DATA--
return ['array1' => [3, 1], 'array2' => ['foo', 'bar'], 'array3' => ['a' => ['e' => 'h'], 'b' => ['f' => 'i'], 'c' => ['g' => 'j']], 'traversable' => new \ArrayObject([0 => 3, 1 => 2, 2 => 1])]
--EXPECT--
2
2
3
3
10 changes: 10 additions & 0 deletions tests/Fixtures/filters/shuffle_with_alphanumerics_characters.test
@@ -0,0 +1,10 @@
--TEST--
Exception for invalid argument type in "shuffle" filter call
--TEMPLATE--
{{ array1|shuffle }}
{{ array2|shuffle }}
--DATA--
return ['array1' => 'Hello World', 'array2' => 1234]
--EXCEPTION--
The shuffle filter only works with array or "Traversable", got "string" as argument.
The shuffle filter only works with array or "Traversable", got "integer" as argument.
8 changes: 8 additions & 0 deletions tests/Fixtures/filters/shuffle_with_boolean.test
@@ -0,0 +1,8 @@
--TEST--
Exception for invalid argument type in "shuffle" filter call
--TEMPLATE--
{{ array|shuffle }}
--DATA--
return ['array' => false]
--EXCEPTION--
The shuffle filter only works with array or "Traversable", got "boolean" as argument.
8 changes: 8 additions & 0 deletions tests/Fixtures/filters/shuffle_with_empty_string.test
@@ -0,0 +1,8 @@
--TEST--
Exception for invalid argument type in "shuffle" filter call
--TEMPLATE--
{{ array|shuffle }}
--DATA--
return ['array' => '']
--EXCEPTION--
The shuffle filter only works with array or "Traversable", got "string" as argument.
8 changes: 8 additions & 0 deletions tests/Fixtures/filters/shuffle_with_null_value.test
@@ -0,0 +1,8 @@
--TEST--
Exception for invalid argument type in "shuffle" filter call
--TEMPLATE--
{{ array|shuffle }}
--DATA--
return ['array' => null]
--EXCEPTION--
The shuffle filter only works with array or "Traversable", got "NULL" as argument.

0 comments on commit 3e94978

Please sign in to comment.