Prácticas para desarrolladores

Instalación

La mejor manera de instalar Latte es utilizar un Compositor:

composer require latte/latte

Versiones PHP soportadas (se aplica a las últimas versiones del parche Latte):

versión compatible con PHP
Latte 3.0 PHP 8.0 – 8.2
Latte 2.11 PHP 7.1 – 8.2
Latte 2.8 – 2.10 PHP 7.1 – 8.1

Cómo renderizar una plantilla

¿Cómo renderizar una plantilla? Utilice este sencillo código:

$latte = new Latte\Engine;
// cache directory
$latte->setTempDirectory('/path/to/tempdir');

$params = [ /* template variables */ ];
// or $params = new TemplateParameters(/* ... */);

// render to output
$latte->render('template.latte', $params);
// or render to variable
$output = $latte->renderToString('template.latte', $params);

Los parámetros pueden ser matrices o incluso mejor objeto, que proporcionará la comprobación de tipo y sugerencia en el editor.

También puedes encontrar ejemplos de uso en el repositorio Latte examples.

Rendimiento y caché

Las plantillas Latte son extremadamente rápidas, porque Latte las compila directamente en código PHP y las almacena en caché en disco. Por lo tanto, no tienen sobrecarga adicional en comparación con las plantillas escritas en PHP puro.

La caché se regenera automáticamente cada vez que se modifica el fichero fuente. Así que puede editar cómodamente sus plantillas Latte durante el desarrollo y ver los cambios inmediatamente en el navegador. Puede desactivar esta característica en un entorno de producción y ahorrar un poco de rendimiento:

$latte->setAutoRefresh(false);

Cuando se despliega en un servidor de producción, la generación inicial de caché, especialmente para aplicaciones grandes, puede tardar un poco. Latte tiene incorporada una prevención contra la estampida de caché. Esta es una situación en la que el servidor recibe un gran número de peticiones concurrentes y debido a que la caché de Latte aún no existe, todas ellas la generarían al mismo tiempo. Lo que dispara la CPU. Latte es inteligente, y cuando hay múltiples peticiones concurrentes, sólo el primer hilo genera la caché, los demás esperan y luego la usan.

Parámetros como clase

Mejor que pasar variables a la plantilla como arrays es crear una clase. Obtienes notación de tipo seguro, buena sugerencia en IDE y una forma de registrar filtros y funciones.

class MailTemplateParameters
{
	public function __construct(
		public string $lang,
		public Address $address,
		public string $subject,
		public array $items,
		public ?float $price = null,
	) {}
}

$latte->render('mail.latte', new MailTemplateParameters(
	lang: $this->lang,
	subject: $title,
	price: $this->getPrice(),
	items: [],
	address: $userAddress,
));

Desactivación de la salida automática de variables

Si la variable contiene una cadena HTML, puede marcarla para que Latte no la escape automáticamente (y por tanto doblemente). Esto evita la necesidad de especificar |noescape en la plantilla.

La forma más sencilla es envolver la cadena en un objeto Latte\Runtime\Html:

$params = [
	'articleBody' => new Latte\Runtime\Html($article->htmlBody),
];

Latte tampoco escapa todos los objetos que implementan la interfaz Latte\HtmlStringable. Así que puedes crear tu propia clase cuyo método __toString() devuelva código HTML que no será escapado automáticamente:

class Emphasis extends Latte\HtmlStringable
{
	public function __construct(
		private string $str,
	) {
	}

	public function __toString(): string
	{
		return '<em>' . htmlspecialchars($this->str) . '</em>';
	}
}

$params = [
	'foo' => new Emphasis('hello'),
];

El método __toString debe devolver HTML correcto y proporcionar escapado de parámetros, ¡de lo contrario puede producirse una vulnerabilidad XSS!

Cómo extender Latte con filtros, etiquetas, etc.

¿Cómo añadir un filtro personalizado, función, etiqueta, etc. a Latte? Descúbrelo en el capítulo Extendiendo Latte. Si quieres reutilizar tus cambios en diferentes proyectos o si quieres compartirlos con otros, entonces debes crear una extensión.

Cualquier código en la plantilla {php ...}

Dentro de la etiqueta {do} por lo que no puede, por ejemplo, insertar construcciones como if ... else o sentencias terminadas en punto y coma.

Sin embargo, puede registrar la extensión RawPhpExtension, que añade la etiqueta {php ...}, que puede utilizarse para insertar cualquier código PHP bajo la responsabilidad del autor de la plantilla.

$latte->addExtension(new Latte\Essential\RawPhpExtension);

Traducción en plantillas

Utilice la extensión TranslatorExtension para añadir {_...}, {translate} y filtrar translate a la plantilla. Se utilizan para traducir valores o partes de la plantilla a otros idiomas. El parámetro es el método (PHP callable) que realiza la traducción:

class MyTranslator
{
	public function __construct(private string $lang)
	{}

	public function translate(string $original): string
	{
		// create $translated from $original according to $this->lang
		return $translated;
	}
}

$translator = new MyTranslator($lang);
$extension = new Latte\Essential\TranslatorExtension(
	$translator->translate(...), // [$translator, 'translate'] in PHP 8.0
);
$latte->addExtension($extension);

El traductor es llamado en tiempo de ejecución cuando la plantilla es renderizada. Sin embargo, Latte puede traducir todos los textos estáticos durante la compilación de la plantilla. Esto ahorra rendimiento porque cada cadena se traduce sólo una vez y la traducción resultante se escribe en el archivo compilado. Esto crea múltiples versiones compiladas de la plantilla en el directorio caché, una para cada idioma. Para ello, sólo tiene que especificar el idioma como segundo parámetro:

$extension = new Latte\Essential\TranslatorExtension(
	$translator->translate(...),
	$lang,
);

Por texto estático entendemos, por ejemplo, {_'hello'} o {translate}hello{/translate}. El texto no estático, como {_$foo}, seguirá traduciéndose en tiempo de ejecución.

La plantilla también puede pasar parámetros adicionales al traductor a través de {_$original, foo: bar} o {translate foo: bar}, que recibe como matriz $params:

public function translate(string $original, ...$params): string
{
	// $params['foo'] === 'bar'
}

Depuración y Tracy

Latte intenta que el desarrollo sea lo más agradable posible. A efectos de depuración, existen tres etiquetas {dump}, {debugbreak} y {trace}.

Obtendrás la mayor comodidad si instalas la gran herramienta de depuración Tracy y activas el plugin Latte:

// enables Tracy
Tracy\Debugger::enable();

$latte = new Latte\Engine;
// activates Tracy's extension
$latte->addExtension(new Latte\Bridges\Tracy\TracyExtension);

Ahora verás todos los errores en una pulcra pantalla roja, incluidos los errores en plantillas con resaltado de filas y columnas (vídeo). Al mismo tiempo, en la esquina inferior derecha, en la llamada Tracy Bar, aparece una pestaña para Latte, donde puedes ver claramente todas las plantillas renderizadas y sus relaciones (incluyendo la posibilidad de hacer clic en la plantilla o en el código compilado), así como las variables:

Dado que Latte compila las plantillas en código PHP legible, puede recorrerlas cómodamente en su IDE.

Linter: Validando la Sintaxis de la Plantilla

La herramienta Linter le ayudará a revisar todas las plantillas y comprobar si hay errores de sintaxis. Se ejecuta desde la consola:

vendor/bin/latte-lint <path>

Si utiliza etiquetas personalizadas, cree también su Linter personalizado, por ejemplo custom-latte-lint:

#!/usr/bin/env php
<?php

// enter the actual path to the autoload.php file
require __DIR__ . '/vendor/autoload.php';

$linter = new Latte\Tools\Linter($engine);
$linter->scanDirectory($path);

$engine = new Latte\Engine;
// registers individual extensions here
$engine->addExtension(/* ... */);

$path = $argv[1];
$linter = new Latte\Tools\Linter(engine: $engine);
$ok = $linter->scanDirectory($path);
exit($ok ? 0 : 1);

Carga de plantillas desde una cadena

¿Necesita cargar plantillas a partir de cadenas en lugar de archivos, quizás con fines de prueba? StringLoader le ayudará:

$latte->setLoader(new Latte\Loaders\StringLoader([
	'main.file' => '{include other.file}',
	'other.file' => '{if true} {$var} {/if}',
]));

$latte->render('main.file', $params);

Manejador de Excepciones

Puede definir su propio manejador para las excepciones esperadas. Las excepciones que se produzcan dentro de {try} y en el sandbox se le pasan.

$loggingHandler = function (Throwable $e, Latte\Runtime\Template $template) use ($logger) {
	$logger->log($e);
};

$latte = new Latte\Engine;
$latte->setExceptionHandler($loggingHandler);

Búsqueda automática de diseños

Mediante la etiqueta {layout} la plantilla determina su plantilla padre. También es posible que el diseño se busque automáticamente, lo que simplificará la escritura de plantillas, ya que no tendrán que incluir la etiqueta {layout}.

Esto se consigue de la siguiente manera:

$finder = function (Latte\Runtime\Template $template) {
	if (!$template->getReferenceType()) {
		// it returns the path to the parent template file
		return 'automatic.layout.latte';
	}
};

$latte = new Latte\Engine;
$latte->addProvider('coreParentFinder', $finder);

Si la plantilla no debe tener diseño, lo indicará con la etiqueta {layout none}.