10 Tips y características básicas de Twig que todo desarrollador debería conocer

10 Tips y características básicas de Twig que todo desarrollador debería conocer

Twig es un motor de plantilla para el lenguaje de programación PHP. Su sintaxis se origina en las plantillas de Jinja y Django. Es un producto de código abierto con licencia BSD y mantenido por Fabien Potencier. La versión inicial fue creada por Armin Ronacher.

Además de ser uno de los motores de plantillas para PHP con más características, Twig es tambien uno de los más rápidos:

Librería Tiempo(seg) Memoría (kilo octet) Plantillas renderizadas por segundo
Twig 3 1,190 3,333
PHPTAL 3.8 2,100 2,632
Dwoo 6.9 1,870 1,449
Smarty 2 12.9 2,350 775
Smarty 3 14.9 3,230 671
Calypso 34.3 620 292
eZ Templates 53 5,850 189

Twig es la manera más fácil de hacer las plantillas de tu proyecto en PHP menos confusas y más sencillas de leer. En este artículo, compartiremos contigo 10 tips que todo desarrollador o diseñador debería conocer al trabajar con Twig.

10. Declaración de variables

Puedes asignar valores en variables dentro de bloques usando el tag set:

{% set fooA = 'foo' %}
{% set fooB = [1, 2] %}
{% set fooC = {
    'foo': 'bar',
    'foo2': 'bar2',
    'grupo': fooB
} %}

{{ fooC.foo }}
{{ fooC.grupo[0]}}

Twig te permite manipular multiples valores y tipos de objetos en variables. Puedes manipular estos objetos usando una notación de tipo JSON y JavaScript. Es decir, puedes usar un punto (.) para acceder a atributos de una variable en caso de que esta sea un objeto (métodos e incluso items de un array de PHP enviado desde el controlador), o la así llamada notación de subindices ([indice]).

Vale la pena destacar que si una propiedad fue nombrada con caracteres especiales (como puntos o simbolos menos : miVariable.mi-propiedad ó miVariable.mi.propiedad), necesitarás accederla usando la función attribute de Twig para no provocar ningun tipo de error:

{{ attribute(myVariable, 'my-property') }}

{{ attribute(myVariable, 'my.property') }}

9. Interpolación de cadenas de texto

De la misma manera en que PHP puede concatenando variables dentro de una cadena de texto son comillas dobles:

<?php

$hello = "Hi";

echo "Inline $hello";
// Imprime : Inline Hi

$myVariable = "Hola {$hello}";
echo $myVariable;
// Imprime: "Hola Hi"

Twig ofrece soporte para esta característica tambien y te permite incluso ejecutar operaciones en linea como la concatenación y matemáticas:

{% set name = 'Buddy' %}
 
{{ "Hola #{name}, como estás hoy?" }}
Hola Buddy, como estás hoy?

{{ "Operación matemática =  #{(1 + 2) * (4 * 5)}" }}
Operación matemática =  60

Nota

Si quieres interpolar, deberás usar al igual que en PHP comillas dobles (" "), si usas comillas sencillas (' ') la interpolación no se usa.

8. La variable loop dentro de un bucle for y tag else

Dentro de un bloque {%for%} puedes acceder a la variable especial loop que contiene las siguientes propiedades:

Variable Descripción
loop.index La iteración actual del bucle. (con índice inicial 1)
loop.index0 La iteración actual del bucle. (con índice inicial 0)
loop.revindex El número de iteraciones desde el final del bucle (con índice inicial 1)
loop.revindex0 El número de iteraciones desde el final del bucle (con índice inicial 0)
loop.first True si es la primera iteración
loop.last True si es la ultima iteración
loop.length El número de elementos de la secuencia
loop.parent El contexto padre

Por ejemplo, para verificar si un item es la ultima iteración del bucle, puedes usar:

{% for user in users %}
    {% if loop.last %}
        {{"Last user is : " ~ user.username}}
    {% else %}
        {{user.username}}
    {% endif %}
{% endfor %}

Notas

Las propiedades loop.length, loop.revindex, loop.revindex0, y loop.last solo están disponibles para arrays de PHP u objetos que implementan la interfaz Countable. Tampoco están disponibles dentro de un bucle con condición.

Aunque el tag {%for%} no es un tag {%if%} (no me digas ...), este soporta el tag  {%else%}. En este caso, el bucle crea automaticamente una condición que se ejecuta cuando una variable a iterar está vacía:

<ul>
    {% for user in users %}
        <li>{{ user.username|e }}</li>
    {% else %}
        <li><em>No hay usuarios disponibles</em></li>
    {% endfor %}
</ul>

Aunque el tag  {%else%} es bastante util, puedes verificar tambien si una variable es iterable o no usando la condición iterable:

{# Evalua True si el valor de foo es iterable  #}
{% if users is iterable %}
    {% for user in users %}
        Hola {{ user }}!
    {% endfor %}
{% else %}
    {# users es probablemente solo texto #}
    Hola {{ users }}!
{% endif %}

Algunas veces, con bucles anidados, necesitarás el acceso al contexto padres. Este contexto es accessible siempre usando la propiedad loop.parent. Por ejemplo, si tienes la siguiente información para la plantilla:

{% set data = {
    'topics' : {
        'topic1' : ['Message 1 of topic 1', 'Message 2 of topic 1'],
        'topic2' : ['Message 1 of topic 2', 'Message 2 of topic 2'],
    }
}%}

{% for topic, messages in data.topics %}
    * {{ loop.index }}: {{ topic }}
  {% for message in messages %}
      - {{ loop.parent.loop.index }}.{{ loop.index }}: {{ message }}
  {% endfor %}
{% endfor %}

El resultado debería ser algo como:

* 1: topic1
        - 1.1: Message 1 of topic 1
        - 1.2: Message 2 of topic 1
    * 2: topic2
        - 2.1: Message 1 of topic 2
        - 2.2: Message 2 of topic 2

7. Extender un bloque sin remover el contenido existente

Si tienes un bloque que está localizado en una plantilla contenedora, por ejemplo base.html.twig y necesitas agregar algo de contenido a este bloque en una plantilla menor, por ejemplo child.html.twig, puedes crear un bloque con el mismo nombre en la plantilla hija y usar la función parent() para obtener el contenido generado del bloque original. Sin el método parent, el contenido solamente sería reemplazado y el contenido de la plantilla no existiría.

{# parent-index.html.twig#}

{%block toolbar -%}
    <a href="path_to_something">
        User Normal Action 1
    </a>
    <a href="path_to_something">
        User Normal Action 2
    </a>
{%endblock%}

{# child-template.html.twig#}

{%block toolbar -%}
    {# The content of the base.html.twig will be retrieved and printed in this inherited view too#}
    {{parent()}}
    
    <a href="path_to_something">
        User Normal Action 3
    </a>
    <a href="path_to_something">
        User Normal Action 4
    </a>
{%endblock%}

{#
    Final Output in the child-template :

    <a href="path_to_something">
        User Normal Action 1
    </a>
    <a href="path_to_something">
        User Normal Action 2
    </a>
    <a href="path_to_something">
        User Normal Action 3
    </a>
    <a href="path_to_something">
        User Normal Action 4
    </a>
#}

6. Twig soporta expresiones regulares

Twig tiene asombrosas y utiles funciones para tareas básicas y frecuentemente usadas con cadenas de texto como starts and ends with (inicia y finaliza con):

{% if 'Batman' starts with 'B' %}

{% else%}
    
{% endif %}

{% if 'Batman' ends with 'n' %}

{% else%}
    
{% endif %}

Sin embargo, no todo en la vida puede ser arreglado verificando si una cadena de texto finaliza o inicia con otra. A veces necesitarás hacer complejos mecanismos de comparación que pueden ser resueltos generalmente solo con Regex.

Twig soporta expresiones regulares y te permite usarlas con el comparador matches:

{% if "mail@mail.com" matches '/^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,})$/' %}
    {{"Es un email válido"}}
{% else %}
    {{"Parece que tu email no es válido."}}
{% endif %}

5. Controlar espacios al imprimir variables

Twig incluye cualquier espacio dentro de un bloque, por ejemplo:

{% for i in 1..10 %}
    {{i}}
{% endfor %}

{# Imprime:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
#}

Sin embargo, puedes prevenir este comportamiento fácilmente. Twig te permite limpiar espacios innecesarios de 2 maneras:

  • Controlar espacios a nivel de bloque
  • Usando el tag {% spaceless %} .

Al controlar espacios a nivel de bloque, que permite removes espacios de todo lo que imprimes, para usarlo incluye un simbolo menos antes y despues (respectivamente) de cada tag de impresión:

{% for i in 1..10 %}
    {# Nota el - al inicio y final #}
    {{- i -}}
{% endfor %}

{# Imprime :
    12345678910
#}

Nota que puedes aplicarlo a un solo lado de impresión:

<li>    {{- "Texto" }}    </li>

{# imprime '<li>Texto    </li>' #}

<li>    {{ "Texto" -}}    </li>

{# imprime '<li>    Texto</li>' #}

While the spaceless tag allow you to print an HTML block without spaces (which provides a minifier effect) :

{% spaceless %}
    <div>
        <strong>Hey, no easy readable HTML</strong>
    </div>
{% endspaceless %}

{# output will be <div><strong>Hey, no easy readable HTML</strong></div> #}

4. Pretty print JSON con twig

Twig soporta el uso de constantes de PHP usando el método constant. En PHP se puede imprimir de manera identada una cadena JSON usando la constante JSON_PRETTY_PRINT como parámetro a la función json_encode:

<?php

$json_string = json_encode($data, JSON_PRETTY_PRINT);

Twig usa el mismo método tras bambalinas, por lo tanto debes usar la misma constante:

{% set data = {
    "Hey": "Ho",
    "What": 12,
    "Value" : true
}%}

{{ data|json_encode()|raw }}

{{ data|json_encode(constant('JSON_PRETTY_PRINT'))}}

{# Imprimer:
{# Si aparecen símbolos HTML , usa el filtro |raw despues de la función json_encode#}

{"Hey":"Ho","What":12,"Value":true}

{
    "Hey": "Ho",
    "What": 12,
    "Value": true
}
#}

3. Modificar fechas

Con Twig puedes modificar fechas fácilmente como lo haces con la clase DateTime en PHP:

<?php
$date = new DateTime('2000-12-31');

$date->modify('+1 month');
echo $date->format('Y-m-d') . "\n";
//2001-01-31

$date->modify('+1 month');
echo $date->format('Y-m-d') . "\n";
//2001-03-03
?>

En este caso, usa el filtro date_modify:

{{ "now"|date_modify('+1 month')|date('Y-m-d')}}

2. Limitar longitud de una cadena de texto

En muchas ocasiones necesitarás limitar la cantidad de caracteres que se muestran al imprimir una variable de texto. Para controlar esta cantidad usa el filtro slice:

{% set myTextVariable = "A semi long string"%}

{{myTextVariable|slice(0,10)}}
{# Outputs : A semi lon #}

Puedes incluso usar el operador ternario para limitar la longitud y agregar puntos suspensivos al final: 

{% set myTextVariable = "Una cadena de texto muy larga "%}

{# Si la longitud de la cadena de texto es de más de 50 caracteres, cortar el sobrantey agregar 3 puntos al final, de otra manera imprimir variable normalmente #}
{{ myTextVariable|length > 50 ? myTextVariable|slice(0, 10) ~ '...' : myTextVariable }}

{# Que es lo mismo que : #}

{% if myTextVariable|length > 50 %}
    {{ myTextVariable|slice(0, 10) ~ '...'}}
{% else %}
    {{ myTextVariable }}
{% endif %}

1. Usar macros

Los macros son comparables con funciones en lenguages de programación regulares. Son utiles para generar bloques de HTML reusables para no repetir tanto tu código.

Basica y teoricamente: es un tipo de función de Twig autoescrita que imprime HTML a partir de parámetros enviados (que pueden ser nulos).

Los macros necesitan estár localizados en archivos diferentes como buena practica para ser incluidos luego en la plantilla general usando el tag import:

{% import "forms.html" as forms %}

Sin embargo, puedes agregar macros en donde desees. En caso de que quieras agregarlos en el mismo archivo en el que estás trabajando puedes usar la variable _self:

{% import _self as forms %}

Puedes usar macros para imprimir bloques de HTML repetitivos como formularios. En el siguiente ejemplo usamos un macro para generar un formulario de bootstrap:

{% macro input(name, value, type, size) %}
    <div class="form-group">
        <input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}" />
    </div>
{% endmacro %}

{% import _self as forms %}

<form action="register.php" method="post">
    {{forms.input("frm_username",null,"text")}}
    {{forms.input("frm_password",null,"password")}}
    {{forms.input("frm_email",null,"email")}}
    {{forms.input("frm_birthday",null,"date")}}
    {{forms.input("frm_submit","Register","submit")}}
</form>

Y el resultado sería algo similar a :

<form action="register.php" method="post">
        <div class="form-group">
        <input type="text" name="frm_username" value="" size="20" />
    </div>

        <div class="form-group">
        <input type="password" name="frm_password" value="" size="20" />
    </div>

        <div class="form-group">
        <input type="email" name="frm_email" value="" size="20" />
    </div>

        <div class="form-group">
        <input type="date" name="frm_birthday" value="" size="20" />
    </div>

        <div class="form-group">
        <input type="submit" name="frm_submit" value="Register" size="20" />
    </div>

</form>

Puedes ver un macro en funcionamiento en el siguiente fiddle:

Preguntas frecuentes de Twig

Cómo concatenar cadenas de texto en Twig

En PHP puedes concatenar cadenas de texto usando un punto (.). En Twig deberás usar el símbolo  ~ (tilde):

{{"Hola " ~ app.user.username ~ " cómo estás hoy?"}}

Puedes usar en su defecto interpolación de cadenas de texto como mencionado en el punto número 9.

Cómo verificar si una variable existe

De acuerdo a la configuración de tu entorno Twig, podrás verificar si una variable existe para prevenir errores.

Para verificar si una variable existe use la condición is defined.

{# Descomenta esta variable para ver el contenido del siguiente bloque
    {% set variable = 12 %}
#}

{% if variable is defined %}
    {{- "Variable existe:" ~ variable -}}
{% endif%}

Como verificar si una cadena de texto o un array contiene un valor

Si quieres verificar si un objeto contiene un valor especifico, ya sea cadena de texto (verificar que una cadena de texto existe dentro de otra) o si un valor está dentro de un array, puedes usar el comparador in:

{% set mytext = "hola como estás hoy" %}

{% set myarray = ["Hola",12,15,"otro texto"] %}

{% if "hola" in mytext %}
    {{"'hola' se encontro en el texto"}}
{% endif %}

{% if "Hola" or 12 in myarray %}
    {{"12 u Hola se encontro en el array"}}
{% endif %}

Extra

Puedes probar tus snippets de Twig en linea usando el asombroso Twig Fiddle (twigfiddle.com) que es más rápido y accesible que crear un entorno de desarrollo en Twig.

Que te diviertas !

Esto podría ser de tu interes

Conviertete en un programador más sociable