Twig Arrays and Objects

Objectives
  • Describe how to use arrays inside Twig.
  • Describe how to use objects inside Twig.
  • List the different notations Twig supports for accessing array elements or object properties/methods.
  • Describe the potential impact access modifiers in an injected PHP object have on the availability of the object's properties/methods inside Twig.
Prerequisites
  • Basic experience working with PHP arrays, including their numerical and string-based indexes.
  • Basic experience working with PHP objects, including the use of access modifiers of properties and methods.
Last revision:

Overview

When applications instruct Twig to transform data into HTML, they must provide Twig with at least two things: the name of the template file to render and the PHP variable(s) to be made available (injected) into the template.

You can inject any type of PHP variable, including:

  • scalar types like strings, integers, and booleans (true/false)
  • compound types like arrays and objects    

In this unit we'll discuss working with compound types (PHP arrays and PHP objects) inside Twig templates.

Refresher on PHP Arrays and Objects

PHP Arrays

  • Arrays are lists of key/value pairs.
  • Array keys can be integers or strings.
  • If no keys (indexes) are provided, numerical keys are used automatically, starting at 0.

Examples

[ "Eva", "John", "Anna" ]

→ List of three values. No keys were given, so "Eva" gets key/index 0, "John" gets key/index 1, and "Anna" gets key/index  2.

[
 96 => "Eva", 
 12 => "John",
 879 => "Anna
]

→ List of three key/value pairs with explicitly provided numerical keys (integers).

 [
 'id' => 42,
 'name' => 'Arthur Dent',
 'country' => 'UK'
]

→ list of three key/value pairs with explicitly provided named keys (strings).

[
 'id' => 123,
 'name' => 'Daouda Anani',
 'country' => 'Palestine',
 'hobbies' => [ "reading", "rock climbing" ]
]

→ list of four key/value pairs with explicitly provided named keys; the element with 'hobbies' as a key is itself an array with two elements without explicit keys.

 [
 'sequence' => 126413,
 'origin' => 'compiler',
 'profile' => $profile
]

→ list of three key/value pairs with explicitly provided named keys; the element with 'profile' as key is itself an object.

PHP Objects

  • Like arrays, objects are compound data types; they typically contain more than one value.
  • Objects are instances of predefined classes.
  • Objects typically contain properties (variables) and methods (functions).

Examples

$user = new User();
$user->name = "Sara";
$user->age = 63;

→ $user is an instance of the User class. The "name" and "age" properties have been given a value, and can be retrieved with $user->name and $user->age respectively.

$dog = new Canine();
$dog->size = "large";
$dog->bark();

→  $dog is an instance of the Canine class. Its "size" property is set to "large", and its bark() method is called.

$alex = new Member();
$sal = new Member();
$alex->partner = $sal;

→ $sal and $alex are instances of the Member class. The "partner" property on $alex is set to $sal.

Arrays in Twig

Sequences

Lists of values without explicitly defined keys are called sequences.

Let's assume the following PHP array $colours is injected into a Twig template:

$colours = [ "red", "green", "blue"];

Accessing the values:

in PHPin TwigOutput
print $colours[0];{{ colours.0 }}red
 {{ colours[0] }}red
   
print $colours[1];{{ colours.1 }}green
 {{ colours[1] }}green

Mappings

Lists of values with explicitly defined keys are called mappings.

Let's assume the following PHP array $shapes is injected into a Twig template:

$shapes = [ 
 'ci' => "circle", 
 'sq' => "square"
];

Accessing the values:

in PHPin TwigOutput
print $shapes['sq'];{{ shapes.sq }}square
 {{ shapes['sq'] }}square

Conclusion

In Twig, to address a specific element in an array, whether Twig considers it to be a sequence or a mapping, you can use:

  • the dot notation (shapes.sq)
  • square bracket notation (shapes['sq'])

For consistency reasons it is recommended to always use the dot-notation when you can.

In some more advanced cases (such as using a variable as array key), you have no choice and must use the square bracket notation. 

Objects in Twig

Use the dot notation to access an object's properties and methods in Twig.

Basic example

Let's assume the following PHP Object $item is injected into a Twig template:

class Vegetable {
   public $colour;
   public function getColour() {
       return $this->colour;
   }
}
$item = new Vegetable();
$item->colour = "green"

Accessing the properties and methods:

in PHPin TwigOutput
print $item->colour;{{ item.colour }}green
 {{ item['colour'] }}[empty - not supported]
   
print $item->getColour();{{ item.getColour }}green
 {{ item.getColour() }}green
   
   
 {{ item['getColour'][empty - not supported]
 {{ item['getColour()'][empty - not supported]

Example with access modifiers

In a PHP class definition, properties and methods have access modifiers that specify their accessibility or visibility:

  • public (accessible to everyone)
  • private (only accessible to methods inside the class
  • protected (only accessible to methods inside the class and methods inside child classes)

Twig understands and respects all access modifiers inside injected objects. If a property or method is set to private, for example, you will NOT be able to call this method inside Twig.

Let's assume the following PHP Object $apple is injected into a Twig template. 

class Fruit {
  private $size;
  public __construct($size) {
    $this->setSize($size);
  }
  public function getSize() {
      return $this->size;
  }
  private function setSize($size) {
      $this->size = $size;
  }
}

$apple = new Fruit("small");

Accessing the properties and methods:

in PHPin TwigOutput
print $apple->size{{ apple.size }}[empty (private) - do not use]
   
print $item->getSize(){{ item.getSize }}small
 {{ item.getSize() }}small
   
 {{ item.setSize("large") }}

[empty (private) - do not use]

Even if this method were public, the result would be empty because the setSize() method does not return any values.

Conclusion

In Twig, to address a property or method in an object:

  • use the dot notation
  • remember access modifiers for object properties/methods are respected inside Twig

The square bracket notation, if you choose to use it, is reserved for arrays (sequences or mappings) alone.

Activity 1

Study the following PHP that prepares and injects $variables into your Twig template. The following activities will all be related to this code.

class Product {
   private $price;
   public $name;
   public function __construct($name, $price) {
     $this->name = $name;
     $this->setPrice($price);
   }
   public function getPrice() {
       return $this->price;
   }
   private function setPrice($price) {
       $this->price = $price;
   }
}
$products = [
 new Product("bread", 1),
 new Product("eggs", 2),
 new Product("laptop", 1000)
];
$user = [
 'id' => 42,
 'name' => 'Anita Runarsdottir',
 'roles' => [
     [
       'id' => 6,
       'name' => 'admin',
     ],
     [
       'id' => 9,
       'name' => 'editor',
     ],
     [
       'id' => 8,
       'name' => 'publisher',
     ]
 ]
];

$variables = [
 'products' => $products,
 'user' => $user
];

Activity 2

Assume you are not certain about the contents of the $variables mapping the template receives. You want to inspect $variables to see which keys it contains, so you can later use those keys to address the values inside.

How would you print all the keys in a given mapping?

Activity 3

In your template: print the number of products.

Answer / solution
Number of products: {{ variables.products | length }}

Activity 4

Using a loop, print a list of all products, with the price in brackets:

bread (1)
eggs (2)
...

Answer / solution
{% for product in variables.products %}
{{ product.name }} ({{ product.getPrice }})
{% endfor%}

Activity 5

Print the price of the first product and the name of the last product.

Answer / solution
{% set first_product = variables.products | first %}
price of first product: {{ first_product.getPrice() }}

{% set last_product = variables.products | last %}
name of last product: {{ last_product.name }}

Activity 6

In the following code, the second snippet produces the same result as the first snippet. Can you explain why and/or how this is happening?

First snippet:

{% set first_product = variables.products | first %}
price of first product: {{ first_product.getPrice() }}

 

Second snippet:

price of first product: {{ (variables.products | first).getPrice()  }}
Answer / solution

In the first snippet we assign the first item of a list to a variable, and then call the getPrice() method on that variable.

In the second snippet, instead of assigning the result of variables.products | first to a variable, we place it between brackets to evaluate it as an expression. It silently gets replaced with the correct product, on which we then call getPrice().

In other words, it's a short-hand method to avoid first placing something in an intermediary variable that we won't need for anything else. It allows for shorter code, but may be less easy to read, depending on your preferences.

Activity 7

Print all the roles granted to the injected user. You don't know how many roles the user has, so you must use a loop.

Answer / solution
{% for role in variables.user.roles %}
{{ role.name }}
{% endfor %}

Summary

  • Arrays
    • inside Twig, arrays are called:
      • sequences if their keys are not explicitly set
      • mappings if their keys are explicitly set
    • use the dot notation to address array elements
    • do not use the square bracket notation unless you have no choice
  • Objects
    • use the dot-notation to address properties and methods
    • do not use the square bracket notation at all; it is not supported
    • PHP's public/private/protected access modifiers are respected inside Twig