Este capítulo describe la API de Twig y no el lenguaje de plantillas. Será más útil como referencia para aquellos que implementan la interfaz de plantillas en la aplicación y no para aquellos que crean plantillas Twig.
Twig utiliza un objeto central llamado environment (entorno) (de la clase \Twig\Environment). Las instancias de esta clase se utilizan para almacenar la configuración y extensiones, y se usan para cargar plantillas.
La mayoría de las aplicaciones crean un objeto \Twig\Environment en la inicialización de la aplicación y lo usan para cargar plantillas. En algunos casos, puede ser útil tener múltiples entornos simultáneamente, con diferentes configuraciones.
La forma típica de configurar Twig para cargar plantillas para una aplicación se ve así:
require_once '/path/to/vendor/autoload.php';
$loader = new \Twig\Loader\FilesystemLoader('/path/to/templates');
$twig = new \Twig\Environment($loader, [
'cache' => '/path/to/compilation_cache',
]);
Esto crea un entorno de plantillas con una configuración por defecto y un cargador que busca plantillas en el directorio /path/to/templates/. Hay diferentes cargadores disponibles y también puedes escribir el tuyo propio si quieres cargar plantillas desde una base de datos u otros recursos.
Note
Observa que el segundo argumento del entorno es un array de opciones. La opción cache es un directorio de caché de compilación, donde Twig almacena en caché las plantillas compiladas para evitar la fase de análisis para solicitudes posteriores. Es muy diferente del caché que podrías querer añadir para las plantillas evaluadas. Para tal necesidad, puedes usar cualquier biblioteca de caché PHP disponible.
Para cargar una plantilla, llama al método load() en un entorno de Twig que devuelve una instancia de \Twig\TemplateWrapper:
$template = $twig->load('index.html.twig');
Para renderizar una plantilla con algunas variables, llama al método render():
echo $template->render(['the' => 'variables', 'go' => 'here']);
Note
El método display() es un atajo para mostrar la plantilla renderizada.
También puedes cargar y renderizar la plantilla directamente a través del Environment:
echo $twig->render('index.html.twig', ['the' => 'variables', 'go' => 'here']);
Si una plantilla define bloques, se pueden renderizar individualmente mediante la llamada renderBlock():
echo $template->renderBlock('block_name', ['the' => 'variables', 'go' => 'here']);
Note
Añadido en la versión 3.18
Para transmitir una plantilla, llama al método stream():
$template->stream(['the' => 'variables', 'go' => 'here']);
Para transmitir un bloque de plantilla específico, llama al método streamBlock():
$template->streamBlock('block_name', ['the' => 'variables', 'go' => 'here']);
Note
Los métodos stream() y streamBlock() devuelven un iterable.
Al crear una nueva instancia de \Twig\Environment, puedes pasar un array de opciones como segundo argumento del constructor:
$twig = new \Twig\Environment($loader, ['debug' => true]);
Las siguientes opciones están disponibles:
debug boolean
Cuando se establece en true, las plantillas generadas tienen un método __toString() que puedes usar para mostrar los nodos generados (por defecto es false).
charset string (por defecto utf-8)
El charset utilizado por las plantillas.
cache string o false
Una ruta absoluta donde almacenar las plantillas compiladas, o false para deshabilitar el almacenamiento en caché (que es el valor por defecto).
auto_reload boolean
Al desarrollar con Twig, es útil recompilar la plantilla cada vez que cambia el código fuente. Si no proporcionas un valor para la opción auto_reload, se determinará automáticamente basándose en el valor de debug.
strict_variables boolean
Si se establece en false, Twig ignorará silenciosamente las variables no válidas (variables y/o atributos/métodos que no existen) y las reemplazará con un valor null. Cuando se establece en true, Twig lanza una excepción en su lugar (por defecto es false).
autoescape string
Establece la estrategia de auto-escape por defecto (name, html, js, css, url, html_attr, o un callback PHP que toma el "nombre de archivo" de la plantilla y devuelve la estrategia de escape a usar -- el callback no puede ser un nombre de función para evitar colisión con las estrategias de escape incorporadas); establécelo en false para deshabilitar el auto-escape. La estrategia de escape name determina la estrategia de escape a usar para una plantilla basada en la extensión del nombre de archivo de la plantilla (esta estrategia no incurre en sobrecarga en tiempo de ejecución ya que el auto-escape se hace en tiempo de compilación).
optimizations integer
Una bandera que indica qué optimizaciones aplicar (por defecto es -1 -- todas las optimizaciones están habilitadas; establécelo en 0 para deshabilitar).
use_yield boolean
true: fuerza a las plantillas a usar exclusivamente yield en lugar de echo (todas las extensiones deben estar listas para yield)
false (por defecto): permite a las plantillas usar una mezcla de yield y llamadas echo para permitir una migración progresiva.
Cambia a true cuando sea posible ya que este será el único modo soportado en Twig 4.0.
Los cargadores son responsables de cargar plantillas desde un recurso como el sistema de archivos.
Todos los cargadores de plantillas pueden almacenar en caché las plantillas compiladas en el sistema de archivos para su reutilización futura. Acelera mucho a Twig ya que las plantillas solo se compilan una vez.
Aquí hay una lista de los cargadores incorporados:
\Twig\Loader\FilesystemLoader\Twig\Loader\FilesystemLoader carga plantillas desde el sistema de archivos. Este cargador puede encontrar plantillas en carpetas del sistema de archivos y es la forma preferida de cargarlas:
$loader = new \Twig\Loader\FilesystemLoader($templateDir);
También puede buscar plantillas en un array de directorios:
$loader = new \Twig\Loader\FilesystemLoader([$templateDir1, $templateDir2]);
Con tal configuración, Twig primero buscará plantillas en $templateDir1 y si no existen, recurrirá a buscarlas en $templateDir2.
Puedes añadir o anteponer rutas a través de los métodos addPath() y prependPath():
$loader->addPath($templateDir3);
$loader->prependPath($templateDir4);
El cargador del sistema de archivos también soporta plantillas con espacios de nombres. Esto permite agrupar tus plantillas bajo diferentes espacios de nombres que tienen sus propias rutas de plantilla.
Cuando uses los métodos setPaths(), addPath(), y prependPath(), especifica el espacio de nombres como segundo argumento (cuando no se especifica, estos métodos actúan sobre el espacio de nombres "principal"):
$loader->addPath($templateDir, 'admin');
Las plantillas con espacios de nombres se pueden acceder a través de la notación especial @namespace_name/template_path:
$twig->render('@admin/index.html.twig', []);
\Twig\Loader\FilesystemLoader soporta rutas absolutas y relativas. Se prefieren las rutas relativas ya que hacen que las claves de caché sean independientes del directorio raíz del proyecto (por ejemplo, permite calentar el caché desde un servidor de compilación donde el directorio podría ser diferente del utilizado en los servidores de producción):
$loader = new \Twig\Loader\FilesystemLoader('templates', getcwd().'/..');
Note
Cuando no se pasa la ruta raíz como segundo argumento, Twig usa getcwd() para las rutas relativas.
\Twig\Loader\ArrayLoader\Twig\Loader\ArrayLoader carga una plantilla desde un array PHP. Se le pasa un array de strings vinculados a nombres de plantilla:
$loader = new \Twig\Loader\ArrayLoader([
'index.html.twig' => 'Hello {{ name }}!',
]);
$twig = new \Twig\Environment($loader);
echo $twig->render('index.html.twig', ['name' => 'Fabien']);
Este cargador es muy útil para pruebas unitarias. También se puede usar para proyectos pequeños donde almacenar todas las plantillas en un solo archivo PHP podría tener sentido.
Tip
Cuando uses el cargador Array con un mecanismo de caché, debes saber que se genera una nueva clave de caché cada vez que el contenido de una plantilla "cambia" (la clave de caché siendo el código fuente de la plantilla). Si no quieres que tu caché crezca sin control, debes encargarte de limpiar el archivo de caché antiguo tú mismo.
\Twig\Loader\ChainLoader\Twig\Loader\ChainLoader delega la carga de plantillas a otros cargadores:
$loader1 = new \Twig\Loader\ArrayLoader([
'base.html.twig' => '{% block content %}{% endblock %}',
]);
$loader2 = new \Twig\Loader\ArrayLoader([
'index.html.twig' => '{% extends "base.html.twig" %}{% block content %}Hello {{ name }}{% endblock %}',
'base.html.twig' => 'Will never be loaded',
]);
$loader = new \Twig\Loader\ChainLoader([$loader1, $loader2]);
$twig = new \Twig\Environment($loader);
Al buscar una plantilla, Twig intenta cada cargador por turno y devuelve tan pronto como se encuentra la plantilla. Al renderizar la plantilla index.html.twig del ejemplo anterior, Twig la cargará con $loader2 pero la plantilla base.html.twig se cargará desde $loader1.
Note
También puedes añadir cargadores a través del método addLoader().
Todos los cargadores implementan la \Twig\Loader\LoaderInterface:
interface \Twig\Loader\LoaderInterface
{
/**
* Returns the source context for a given template logical name.
*
* @param string $name The template logical name
*
* @return \Twig\Source
*
* @throws \Twig\Error\LoaderError When $name is not found
*/
public function getSourceContext($name);
/**
* Gets the cache key to use for the cache for a given template name.
*
* @param string $name The name of the template to load
*
* @return string The cache key
*
* @throws \Twig\Error\LoaderError When $name is not found
*/
public function getCacheKey($name);
/**
* Returns true if the template is still fresh.
*
* @param string $name The template name
* @param timestamp $time The last modification time of the cached template
*
* @return bool true if the template is fresh, false otherwise
*
* @throws \Twig\Error\LoaderError When $name is not found
*/
public function isFresh($name, $time);
/**
* Check if we have the source code of a template, given its name.
*
* @param string $name The name of the template to check if we can load
*
* @return bool If the template source code is handled by this loader or not
*/
public function exists($name);
}
El método isFresh() debe devolver true si la plantilla en caché actual sigue siendo fresca, dado el último tiempo de modificación, o false en caso contrario.
El método getSourceContext() debe devolver una instancia de \Twig\Source.
Las extensiones de Twig son paquetes que añaden nuevas características a Twig. Registra una extensión a través del método addExtension():
$twig->addExtension(new \Twig\Extension\SandboxExtension());
Twig viene con las siguientes extensiones incorporadas:
\Twig\Extension\CoreExtension: Define todas las características principales de Twig.\Twig\Extension\DebugExtension: Define la función dump para ayudar a depurar variables de plantilla.\Twig\Extension\EscaperExtension: Añade escape automático de salida y la posibilidad de escapar/desescapar bloques de código.\Twig\Extension\SandboxExtension: Añade un modo sandbox al entorno Twig por defecto, haciendo seguro evaluar código no confiable.\Twig\Extension\ProfilerExtension: Habilita el perfilador de Twig incorporado.\Twig\Extension\OptimizerExtension: Optimiza el árbol de nodos antes de la compilación.\Twig\Extension\StringLoaderExtension: Define la función template_from_string para permitir cargar plantillas desde string en una plantilla.Las extensiones Core, Escaper y Optimizer se registran por defecto.
Esta sección describe las características añadidas por las extensiones incorporadas.
Tip
Lee el capítulo sobre extender Twig para aprender cómo crear tus propias extensiones.
La extensión core define todas las características principales de Twig:
La extensión escaper añade escape automático de salida a Twig. Define una etiqueta, autoescape, y un filtro, raw.
Al crear la extensión escaper, puedes activar o desactivar la estrategia global de escape de salida:
$escaper = new \Twig\Extension\EscaperExtension('html');
$twig->addExtension($escaper);
Si se establece en html, todas las variables en las plantillas se escapan (usando la estrategia de escape html), excepto aquellas que usan el filtro raw:
{{ article.to_html|raw }}
También puedes cambiar el modo de escape localmente usando la etiqueta autoescape:
{% autoescape 'html' %}
{{ var }}
{{ var|raw }} {# var no será escapado #}
{{ var|escape }} {# var no será doblemente escapado #}
{% endautoescape %}
Warning
La etiqueta autoescape no tiene efecto en archivos incluidos.
Las reglas de escape se implementan de la siguiente manera:
Los literales (enteros, booleanos, arrays, ...) usados en la plantilla directamente como variables o argumentos de filtro nunca se escapan automáticamente:
{{ "Twig<br/>" }} {# no será escapado #}
{% set text = "Twig<br/>" %}
{{ text }} {# será escapado #}
Las expresiones cuyo resultado es un literal o una variable marcada como segura nunca se escapan automáticamente:
{{ any_value ? "Twig<br/>" : "<br/>Twig" }} {# no será escapado #}
{% set text = "Twig<br/>" %}
{{ true ? text : "<br/>Twig" }} {# será escapado #}
{{ false ? text : "<br/>Twig" }} {# no será escapado #}
{% set text = "Twig<br/>" %}
{{ any_value ? text|raw : "<br/>Twig" }} {# no será escapado #}
Los objetos con un método __toString se convierten a strings y se escapan. Puedes marcar algunas clases y/o interfaces como seguras para algunas estrategias a través de EscaperExtension::addSafeClass():
// marcar objetos de clase "HtmlGenerator" como seguros para la estrategia HTML
$escaper->addSafeClass('HtmlGenerator', ['html']);
// marcar objetos de interfaz "HtmlGeneratorInterface" como seguros para la estrategia HTML
$escaper->addSafeClass('HtmlGeneratorInterface', ['html']);
// marcar objetos de clase "HtmlGenerator" como seguros para las estrategias HTML y JS
$escaper->addSafeClass('HtmlGenerator', ['html', 'js']);
// marcar objetos de clase "HtmlGenerator" como seguros para todas las estrategias
$escaper->addSafeClass('HtmlGenerator', ['all']);
El escape se aplica antes de imprimir, después de aplicar cualquier otro filtro:
{{ var|upper }} {# es equivalente a {{ var|upper|escape }} #}
El filtro raw solo debe usarse al final de la cadena de filtros:
{{ var|raw|upper }} {# será escapado #}
{{ var|upper|raw }} {# no será escapado #}
El escape automático no se aplica si el último filtro en la cadena está marcado como seguro para el contexto actual (ej. html o js). escape y escape('html') están marcados como seguros para HTML, escape('js') está marcado como seguro para JavaScript, raw está marcado como seguro para todo.
{% autoescape 'js' %}
{{ var|escape('html') }} {# será escapado para HTML y JavaScript #}
{{ var }} {# será escapado para JavaScript #}
{{ var|escape('js') }} {# no será doblemente escapado #}
{% endautoescape %}
Note
Ten en cuenta que el auto-escape tiene algunas limitaciones ya que el escape se aplica en expresiones después de la evaluación. Por ejemplo, cuando se trabaja con concatenación, {{ value|raw ~ other }} no dará el resultado esperado ya que el escape se aplica en el resultado de la concatenación, no en las variables individuales (por lo tanto, el filtro raw no tendrá ningún efecto aquí).
La extensión sandbox se puede usar para evaluar código no confiable. Lee más sobre esto en el capítulo Twig Sandbox.
La extensión profiler habilita un perfilador para plantillas Twig; solo debe usarse en tus máquinas de desarrollo ya que añade cierta sobrecarga:
$profile = new \Twig\Profiler\Profile();
$twig->addExtension(new \Twig\Extension\ProfilerExtension($profile));
$dumper = new \Twig\Profiler\Dumper\TextDumper();
echo $dumper->dump($profile);
Un perfil contiene información sobre tiempo y consumo de memoria para ejecuciones de plantillas, bloques y macros.
También puedes volcar los datos en un formato compatible con Blackfire.io:
$dumper = new \Twig\Profiler\Dumper\BlackfireDumper();
file_put_contents('/path/to/profile.prof', $dumper->dump($profile));
Sube el perfil para visualizarlo (crea una cuenta gratuita primero):
blackfire --slot=7 upload /path/to/profile.prof
La extensión optimizer optimiza el árbol de nodos antes de la compilación:
$twig->addExtension(new \Twig\Extension\OptimizerExtension());
Por defecto, todas las optimizaciones están activadas. Puedes seleccionar las que quieres habilitar pasándolas al constructor:
$optimizer = new \Twig\Extension\OptimizerExtension(\Twig\NodeVisitor\OptimizerNodeVisitor::OPTIMIZE_FOR);
$twig->addExtension($optimizer);
Twig soporta las siguientes optimizaciones:
\Twig\NodeVisitor\OptimizerNodeVisitor::OPTIMIZE_ALL, habilita todas las optimizaciones (este es el valor por defecto).\Twig\NodeVisitor\OptimizerNodeVisitor::OPTIMIZE_NONE, deshabilita todas las optimizaciones. Esto reduce el tiempo de compilación, pero puede aumentar el tiempo de ejecución y la memoria consumida.\Twig\NodeVisitor\OptimizerNodeVisitor::OPTIMIZE_FOR, optimiza la etiqueta for eliminando la creación de la variable loop siempre que sea posible.Twig puede lanzar excepciones:
\Twig\Error\Error: La excepción base para todos los errores.\Twig\Error\SyntaxError: Se lanza para indicar al usuario que hay un problema con la sintaxis de la plantilla.\Twig\Error\RuntimeError: Se lanza cuando ocurre un error en tiempo de ejecución (cuando un filtro no existe, por ejemplo).\Twig\Error\LoaderError: Se lanza cuando ocurre un error durante la carga de la plantilla.\Twig\Sandbox\SecurityError: Se lanza cuando se llama a una etiqueta, filtro o método no permitido en una plantilla en sandbox.