Use variable as key in a Twig array

Share Button

Lire la version française

Today, I encountered an “issue” when using numeric variable as key in a Twig array.
This is a very specific problem which is due to the use of the array_merge php function. The documentation tells that “values in the input array with numeric keys will be renumbered”. So my goal here is not to explain the reasons of this behaviour but rather explaining my problem, and propose a solution.

The original Twig array

{% set array =
    {
        0:{'numeric':20,'text':'twenty'},
        1:{'numeric':40,'text':'forty'},
        2:{'numeric':10,'text':'ten'},
        3:{'numeric':30,'text':'thirty'}
    }
 %}

{% set loopValues =  [10,20,30,40] %}

Let’s imagine we have the above associative array. The keys are not relevant, the array is not sorted, and we cannot sort it using its keys. The values to use to sort are in the array himself (the ‘numeric’ keys). So, we have to build another temporary array.
In my case, the original array was returned by some Elasticsearch facets and I had to loop on another array (values fetch from database) to display the facets values in the right order (see the code below to understand better)

Build an intermediate array

{# define an empty array #}
{% set tempArray = {} %}

{# and fill it with the 'numeric' as key and the 'text' as value #}
{% for item in array %}
    numeric : {{ item.numeric }}, text : {{ item.text }} <br/ >
    {% set tempArray = tempArray|merge({(item.numeric):(item.text)}) %}
{% endfor %}

{# display the temporary array, only for example purpose, to show you what's wrong #}
{% for key,val in tempArray %}
    {{ key }} : {{ val }} <br/ >
{% endfor %}

{# throws an exception as the keys 10,20,30,40 does not exist #}
{% for val in loopArray %}
    {{ tempArray[val] }} <br/ >
{% endfor %}

Note: Note the parenthesis used in the merge method. They are mandatory to avoid a twig syntax error.

The given result is not the expected one :

numeric : 20, text : twenty
numeric : 40, text : forty
numeric : 10, text : ten
numeric : 30, text : thirty

0 : twenty
1 : forty
2 : ten
3 : thirty

As you see, the ‘numeric’ keys have not been filled as expected in the temporary array. Actually, they have been filled correctly and then renumbered by php. This is a weird behaviour…

The solution

The solution I’ve found is maybe not the better one but it works. As variable numeric keys do not work, we are going to use string keys. See the modified code below and not the “_” I’ve added.

{# we had an extra underscore in the key #}
{% for item in array %}
    numeric : {{ item.numeric }}, text : {{ item.text }}
    {% set tempArray = tempArray|merge({('_'~item.numeric):(item.text)}) %}
{% endfor %}

{% for val in loopArray %}
    {{ tempArray['_'~val] }} <br/ >
{% endfor %}

Now the result is the expected one :

ten
twenty
thirty
forty

Share Button

6 thoughts on “Use variable as key in a Twig array

  1. In twig the merge filter is simply ‘translated’ to php’s array_merge function, and if you try out there this:
    array_merge([], [10 => 'test string']) , you will get the result : [0 => 'test string'], so it’s more of a php thing, rather then twig.

    • And PHP doc says: Values in the input array with numeric keys will be renumbered with incrementing keys starting from zero in the result array.

      So the best solution looks like what you have done, keys as string.

  2. Great tip! I have found that you don’t need to do the string join like:
    tempArray|merge({(‘_’~item.numeric):(item.text)}) %}
    and you can just do:
    tempArray|merge({(item.numeric):item.text}) %}

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Protected by WP Anti Spam