Twig Code Blocks - Working with variables

Objectives
  • Declare and update new single-value variables.
  • Declare and update sequences.
  • Declare and update mappings.
  • Describe the main difference between scalar variables and compound variables.
  • Explain why Twig is limited in its options for working with sequences and mappings.
  • List two alternative ways to manipulate variables to work around Twig's limitations.
Prerequisites
  • Basic experience with PHP arrays, and objects.
Drupal 10
Last revision:

Overview

In this unit you'll learn how to declare and update variables:

  • scalar variables (single values)
  • arrays (sequences and mappings)
  • objects (mappings)

While it's straightforward to declare and update scalar variables, sequences and mappings are not really meant to be updated inside template files.

Twig's philosophy is that complex and extensive manipulations to variables should happen in PHP before they are injected into a template. As a programming language, PHP is very well suited for this.

Inside Twig templates you can perform certain updates to sequences and mappings, but what you can modify and how to do so differs. 

Declaring or updating scalar variables

Scalar variables are variables that hold a single value (string, integer, boolean, ...).

Use the set tag to declare a new variable or update the value of an existing variable.

Example

Twig template

{% set my_var = "hello" %}
{% set total = 100 %}
...
{% set my_var = "goodbye" %}
...
<p>{{ my_var  }}</p>
<p>{{ total  }}</p>

 

Output

<p>goodbye</p>
<p>100</p>

 

Conclusion

You can the set tag to declare a new variable or to update the value of an existing scalar variable.

Declaring or updating arrays

Arrays are lists of values. Twig distinguishes two types of lists:

  • sequences: lists of values without a key
  • mappings: lists of key/value pairs

Declaring arrays

Use the set tag to declare and populate new arrays.

Sequences

Example:

{% set colours = [ 'red', 'green', 'blue' ] %}
<p>First colour: {{ colours.0 }}</p>
<p>Second colour: {{ colours.1 }}</p>
<p>Third colour: {{ colours.2 }}</p>
<p>Fourth colour: {{ colours.3 }}


Output:

<p>First colour: red</p>
<p>Second colour: green</p>
<p>Third colour: blue</p>
<p>fourth colour: </p>


Explanation:

Once you have declared a sequence, you can address its elements via their numerical sequential index, starting at 0.

If you use an index that does not exist, an empty string will be printed, as shown in the "fourth colour" example.

Mappings

Example:

{% 
 set languages = {
   'fr': 'French',
   'ar': 'Arabic'
 } 
%}
<p>fr: {{ languages.fr }}</p>
<p>ar: {{ languages.ar }}</p>
<p>fr: {{ languages.0 }}</p>
<p>ar: {{ languages.1 }}</p>


Output:

<p>fr: French</p>
<p>ar: Arabic</p>
<p>fr: </p>
<p>ar: </p>


Explanation:

Once you have declared a mapping, you can address its elements via their key.

If you use a key that does not exist, an empty string will be printed.

Updating sequences

You may have assumed that the following code to update the first element of a sequence would be correct, but this syntax is INVALID:

{% set colours = [ 'red', 'green', 'blue' ] %}
...
{# INVALID attempt to update a sequence element: #}
{% set colours.0 = 'yellow' %}
{# INVALID attempt to add a sequence element: #}
{% set colours.3 = 'yellow' %}


Error message:

Twig\Error\SyntaxError Unexpected token "punctuation" of value "." ("end of statement block" expected)


Twig's merge filter lets you add or update array elements.

Adding a new element at the end

{% set colours = [ 'red', 'green', 'blue' ] %}
{# Adding a new element at the end: #}
{% set colours = colours | merge([ 'yellow', 'orange' ]) %}
{{ colours.3 }}


Output:

yellow


Explanation:
You can add one or more elements to an array by using the merge filter to merge a new array of elements with the existing array. New elements will be added to the end of the array.


Adding a new element at the beginning

{% set colours = [ 'red', 'green', 'blue' ] %}
{# Adding new element at the beginning: #}
{% set colours = [ 'yellow' ] | merge(colours) %}
{{ colours.0 }}
{{ colours.3 }}


Output:

yellow
blue


Explanation:
We performed the same merge operation, but this time we started with the [ 'yellow' ] sequence and merged in the colours sequence.


Updating an existing element
There is no straightforward way to update an existing element in a sequence. A combination of nested filter calls and the attribute filter does seem to work, but such complex programming inside Twig is discouraged, and not covered here.

The best practice is to manipulate your data before it reaches Twig.

If you absolutely need to do this inside Twig, consider these more advanced approaches:

  • looping through the original array and building a new array with the right elements in the right place.
  • writing a custom Twig filter or function in PHP that handles updating array elements.

Updating mappings

Adding a new element at the end

Twig template:

{% set colours = { 'r': 'red', 'g': 'green', 'b': 'blue' } %}
{% set colours = colours | merge({ 'y': 'yellow' }) %}
{{ colours.r }}
{{ colours.y }}


Output:

red
yellow


Explanation:
Use the merge filter and pass the 2nd mapping as its argument to add the 2nd mapping at the end of the initial mapping.

Adding a new element at the end
Twig template:

{% set colours = { 'r': 'red', 'g': 'green', 'b': 'blue' } %}
{% set colours = { 'y': 'yellow' } | merge(colours) %}
{{ colours.b }}
{{ colours.y }}


Output:

blue
yellow


Explanation:
We performed the same merge operation, but this time we started with the { 'y': 'yellow' } mapping and merged in the colours array.

Updating an existing element

Twig template:

{% set colours = { 'r': 'red', 'g': 'green', 'b': 'blue' } %}
{% set colours = colours | merge({ 'b': 'brown', 'p': 'purple' }) %}
{{ colours.b }}


Output:

brown


Explanation:
When you merge two mappings, and the the second mapping contains keys that are also present in the first mapping, the values from the first mapping will be overwritten (replaced) by the corresponding values form the second mapping.

In the example, we merged the second mapping { 'b': 'brown', 'p': 'purple' } into the first mapping colours. The second mapping contains the 'b' keys, which was already present in the first mapping, so the 'brown' value from the second mapping replaces the 'blue' value from the first mapping.

This syntax is not very clear, and can become quite complex when working with multidimensional arrays / mappings, where values inside a mapping can themselves also be mappings:

{%
 set data = {
   'brussels': { 
     'country': 'Belgium',
     'location': {
       'lat': 50.85045, 
       'long': 4.34878
     }
   }
 }
%}
Latitude: {{ data.brussels.location.lat }}
Longitude: {{ data.brussels.location.long }}

As with sequences, if you need to do more than adding elements to the start or end of a mapping, consider doing so before the data reaches Twig, or write a custom Twig filter or function (advanced).

Activity 1

In the following code sample, which delimiters are used for printing expressions?

{% dump(name) %}

{# dump(name) #}

{{ dump(name) }}
Answer / solution
{{ }}

Activity 2

Your template has access to a variable named main_content.
Write template code to print the content of that variable.

Answer / solution
{{ main_content }}

Activity 3

Assume your template will receive the following variables:

  • first_name = 'Bob'
  • last_name = 'Terwilliger'

Which of the following code samples will produce the requested output? Multiple correct answers or no correct answers are possible.

Output:

Bob Terwilliger


Code samples:


A:

{{ first_name last_name }}


B

{{ first_name }} {{ last_name }}


C:

{{ first_name . ' ' . last_name }}


D:

{{ first_name ~ last_name }}


E:

{{ first_name }} + {{ last_name }}


F:

{{ first_name }} ~ {{ last_name }}


G:

{{ first_name + last_name }}


H:

{{ first_name ~ ' ' ~ last_name }}


I:

{{ first_name.last_name }}
Answer / solution

B and H.

A: syntax error
B: Bob Terwilliger
C: syntax error
D: BobTerwilliger
E: Bob + Terwilliger
F: Bob ~ Terwilliger
G: syntax error
H: Bob Terwilliger
I: empty string (no output)

Activity 4

You can print scalar variables, but you can't print compound variables the same way.

What is the difference between both, and why can't you print compound variables the same way?

Answer / solution

scalar variables hold a single value (number, string, boolean, ...). Compound variables hold multiple values in a special structure like an array (list) or object.

When you try to print a compound variable (e.g. a list called items), Twig does not know how to deal with multiple values. It only knows how to print simple, single values.

Activity 5

What, if any, is the difference between arrays, sequences, and mappings in PHP and Twig?

Answer / solution

Arrays are a compound datatype in PHP. Arrays are lists of values, and each value either has a numerical index or a string.

Twig does not use the term "array". In Twig, arrays with numerical indexes are called "sequences", and arrays with string indexes are called "mappings", and each set of index → value is referred to as a key/value pair.

In Twig, sequences are defined with square brackets; mappings are defined with curly braces.

Summary

  • Declare and update scalar variables with {% set colour = 'red' %}
  • Declare and populate sequences and mappings with:
    • {% set colours = [ 'red', 'green' ] %}
    • {% set colours = { 'r': 'red', 'g': 'green' } %}
  • Add elements to sequences and mappings by using the merge filter to combine the original array with a new array.
  • All other changes to sequences or mappings should be done before the data reaches Twig, or through custom Twig filters/functions to move the complexity from Twig to PHP.
  • Don't forget that Twig is a template language intended for front-end development. Complex data manipulations should be done in PHP, a language that is much better equipped for this task.