Extender Latte

Latte está diseñado pensando en la extensibilidad. Aunque su conjunto estándar de etiquetas, filtros y funciones cubre muchos casos de uso, a menudo necesita añadir su propia lógica específica o herramientas auxiliares. Esta página ofrece una visión general de las formas de extender Latte para que se ajuste perfectamente a los requisitos de su proyecto, desde simples ayudantes hasta complejas sintaxis nuevas.

Formas de extender Latte

Aquí tiene un resumen rápido de las principales formas en que puede personalizar y extender Latte:

  • Filtros personalizados: Para formatear o transformar datos directamente en la salida de la plantilla (por ejemplo, {$var|myFilter}). Ideal para tareas como formatear fechas, modificar texto o aplicar un escape específico. También puede usarlos para modificar bloques más grandes de contenido HTML envolviendo el contenido en un {block} anónimo y aplicándole un filtro personalizado.
  • Funciones personalizadas: Para añadir lógica reutilizable que se puede llamar dentro de expresiones en la plantilla (por ejemplo, {myFunction($arg1, $arg2)}). Útil para cálculos, acceso a funciones auxiliares de la aplicación o generación de pequeñas partes de contenido.
  • Etiquetas personalizadas: Para crear construcciones lingüísticas completamente nuevas ({mytag}...{/mytag} o n:mytag). Las etiquetas ofrecen la mayor flexibilidad, permitiéndole definir sus propias estructuras, controlar el análisis sintáctico de la plantilla e implementar lógica de renderizado compleja.
  • Pasos de compilación: Funciones que modifican el árbol de sintaxis abstracto (AST) de la plantilla después del análisis sintáctico, pero antes de generar el código PHP. Se utilizan para optimizaciones avanzadas, controles de seguridad (como Sandbox) o modificaciones automáticas del código.
  • Loaders personalizados: Para cambiar la forma en que Latte busca y carga los archivos de plantilla (por ejemplo, cargando desde una base de datos, almacenamiento cifrado, etc.).

Elegir el método de extensión correcto es crucial. Antes de crear una etiqueta compleja, considere si un filtro o función más simple sería suficiente. Veamos un ejemplo: implementar un generador de Lorem ipsum que toma como argumento el número de palabras a generar.

  • ¿Como etiqueta? {lipsum 40} – Posible, pero las etiquetas son más adecuadas para estructuras de control o para generar etiquetas complejas. Las etiquetas no se pueden usar directamente en expresiones.
  • ¿Como filtro? {=40|lipsum} – Técnicamente funciona, pero los filtros están diseñados para transformar el valor de entrada. Aquí, 40 es un argumento, no un valor que se transforma. Esto parece semánticamente incorrecto.
  • ¿Como función? {lipsum(40)} – ¡Esta es la solución más natural! Las funciones aceptan argumentos y devuelven valores, lo cual es ideal para usar en cualquier expresión: {var $text = lipsum(40)}.

Recomendación general: Use funciones para cálculos/generación, filtros para transformación y etiquetas para nuevas construcciones lingüísticas o etiquetas complejas. Use pasos para la manipulación del AST y loaders para obtener plantillas.

Registro directo

Para herramientas auxiliares específicas del proyecto o extensiones rápidas, Latte permite el registro directo de filtros y funciones en el objeto Latte\Engine.

Para registrar un filtro, use el método addFilter(). El primer argumento de su función de filtro será el valor antes del carácter | y los argumentos siguientes son los que se pasan después de los dos puntos :.

$latte = new Latte\Engine;

// Definición del filtro (objeto invocable: función, método estático, etc.)
$myTruncate = fn(string $s, int $length = 50) => mb_substr($s, 0, $length);

// Registro
$latte->addFilter('truncate', $myTruncate);

// Uso en la plantilla: {$text|truncate} o {$text|truncate:100}

También puede registrar un Filter Loader, una función que proporciona dinámicamente objetos invocables de filtro según el nombre solicitado:

$latte->addFilterLoader(fn(string $name) => /* devuelve un objeto invocable o null */);

Para registrar una función utilizable en expresiones de plantilla, use addFunction().

$latte = new Latte\Engine;

// Definición de la función
$isWeekend = fn(DateTimeInterface $date) => $date->format('N') >= 6;

// Registro
$latte->addFunction('isWeekend', $isWeekend);

// Uso en la plantilla: {if isWeekend($myDate)}¡Fin de semana!{/if}

Para más información, consulte las secciones Creación de filtros personalizados y Funciones.

Método robusto: Latte Extension

Si bien el registro directo es simple, la forma estándar y recomendada de empaquetar y distribuir extensiones Latte es a través de clases Extension. Una Extension sirve como un punto de configuración central para registrar múltiples etiquetas, filtros, funciones, pasos de compilación y otros elementos.

¿Por qué usar Extensions?

  • Organización: Mantiene las extensiones relacionadas (etiquetas, filtros, etc. para una función específica) juntas en una sola clase.
  • Reutilización y compartición: Empaquete fácilmente sus extensiones para usarlas en otros proyectos o para compartirlas con la comunidad (por ejemplo, a través de Composer).
  • Potencia completa: Las etiquetas personalizadas y los pasos de compilación solo se pueden registrar a través de Extensions.

Registrar una Extension

Una Extension se registra en Latte usando el método addExtension() (o a través del archivo de configuración):

$latte = new Latte\Engine;
$latte->addExtension(new MyProjectExtension);

Si registra múltiples extensiones y definen etiquetas, filtros o funciones con el mismo nombre, la extensión agregada más recientemente tiene prioridad. Esto también significa que sus extensiones pueden sobrescribir etiquetas/filtros/funciones nativas.

Cada vez que realice un cambio en la clase y la actualización automática no esté desactivada, Latte recompilará automáticamente sus plantillas.

Crear una Extension

Para crear su propia extensión, necesita crear una clase que herede de Latte\Extension. Para tener una idea de cómo se ve una extensión de este tipo, eche un vistazo a la CoreExtension integrada.

Veamos los métodos que puede implementar:

beforeCompile (Latte\Engine $engine)void

Se llama antes de compilar la plantilla. El método se puede usar, por ejemplo, para inicializaciones relacionadas con la compilación.

getTags(): array

Se llama al compilar la plantilla. Devuelve un array asociativo nombre de etiqueta ⇒ objeto invocable, que son funciones para analizar sintácticamente etiquetas. Más información.

public function getTags(): array
{
	return [
		'foo' => FooNode::create(...),
		'bar' => BarNode::create(...),
		'n:baz' => NBazNode::create(...),
		// ...
	];
}

La etiqueta n:baz representa un n:atributo puro, es decir, una etiqueta que solo se puede escribir como un atributo.

Para las etiquetas foo y bar, Latte reconoce automáticamente si son etiquetas pares y, si es así, se pueden escribir automáticamente usando n:atributos, incluidas las variantes con los prefijos n:inner-foo y n:tag-foo.

El orden de ejecución de dichos n:atributos está determinado por su orden en el array devuelto por el método getTags(). Por lo tanto, n:foo siempre se ejecuta antes que n:bar, incluso si los atributos en la etiqueta HTML se enumeran en orden inverso como <div n:bar="..." n:foo="...">.

Si necesita especificar el orden de los n:atributos en múltiples extensiones, use el método auxiliar order(), donde el parámetro before o after especifica qué etiquetas se ordenan antes o después de la etiqueta.

public function getTags(): array
{
	return [
		'foo' => self::order(FooNode::create(...), before: 'bar'),
		'bar' => self::order(BarNode::create(...), after: ['block', 'snippet']),
	];
}

getPasses(): array

Se llama al compilar la plantilla. Devuelve un array asociativo nombre de pase ⇒ objeto invocable, que son funciones que representan los llamados pasos de compilación, que recorren y modifican el AST.

Aquí también se puede usar el método auxiliar order(). El valor de los parámetros before o after puede ser * con el significado de antes/después de todo.

public function getPasses(): array
{
	return [
		'optimize' => Passes::optimizePass(...),
		'sandbox' => self::order($this->sandboxPass(...), before: '*'),
		// ...
	];
}

beforeRender (Latte\Engine $engine)void

Se llama antes de cada renderizado de la plantilla. El método se puede usar, por ejemplo, para inicializar variables utilizadas durante el renderizado.

getFilters(): array

Se llama antes de renderizar la plantilla. Devuelve filtros como un array asociativo nombre de filtro ⇒ objeto invocable. Más información.

public function getFilters(): array
{
	return [
		'batch' => $this->batchFilter(...),
		'trim' => $this->trimFilter(...),
		// ...
	];
}

getFunctions(): array

Se llama antes de renderizar la plantilla. Devuelve funciones como un array asociativo nombre de función ⇒ objeto invocable. Más información.

public function getFunctions(): array
{
	return [
		'clamp' => $this->clampFunction(...),
		'divisibleBy' => $this->divisibleByFunction(...),
		// ...
	];
}

getProviders(): array

Se llama antes de renderizar la plantilla. Devuelve un array de proveedores, que suelen ser objetos que usan las etiquetas en tiempo de ejecución. Se accede a ellos a través de $this->global->.... Más información.

public function getProviders(): array
{
	return [
		'myFoo' => $this->foo,
		'myBar' => $this->bar,
		// ...
	];
}

getCacheKey (Latte\Engine $engine)mixed

Se llama antes de renderizar la plantilla. El valor de retorno se convierte en parte de la clave, cuyo hash está contenido en el nombre del archivo de la plantilla compilada. Por lo tanto, para diferentes valores de retorno, Latte generará diferentes archivos de caché.

versión: 3.0