Nette Documentation Preview

syntax
Prácticas para desarrolladores
******************************


Instalación .[#toc-installation]
================================

La mejor manera de instalar Latte es utilizar un Compositor:

```shell
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


Cómo renderizar una plantilla .[#toc-how-to-render-a-template]
==============================================================

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

```php
$latte = new Latte\Engine;
// directorio caché
$latte->setTempDirectory('/path/to/tempdir');

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

// renderizar a la salida
$latte->render('template.latte', $params);
// o renderizar a variable
$output = $latte->renderToString('template.latte', $params);
```

Los parámetros pueden ser matrices o incluso mejor [objeto |#Parameters as a class], que proporcionará la comprobación de tipo y sugerencia en el editor.

.[note]
También puedes encontrar ejemplos de uso en el repositorio [Latte examples |https://github.com/nette-examples/latte].


Rendimiento y caché .[#toc-performance-and-caching]
===================================================

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:

```php
$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é":https://en.wikipedia.org/wiki/Cache_stampede.
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 .[#toc-parameters-as-a-class]
===================================================

Mejor que pasar variables a la plantilla como arrays es crear una clase. Obtienes [notación de tipo seguro |type-system], [buena sugerencia en IDE |recipes#Editors and IDE] y una forma de [registrar filtros |extending-latte#Filters Using the Class] y [funciones |extending-latte#Functions Using the Class].

```php
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,
));
```


Deshabilitando Auto-Escaping de Variable .[#toc-disabling-auto-escaping-of-variable]
====================================================================================

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`:

```php
$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:

```php
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'),
];
```

.[warning]
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. .[#toc-how-to-extend-latte-with-filters-tags-etc]
==================================================================================================

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


Cualquier código en la plantilla `{php ...}` .{toc: RawPhpExtension}
====================================================================

Dentro de la etiqueta [`{do}` |tags#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 ...}`. Puede utilizarla para insertar cualquier código PHP. No está sujeta a ninguna regla del modo sandbox, por lo que su uso es responsabilidad del autor de la plantilla.

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


Comprobación del código generado .[#toc-checking-generated-code]{data-version:3.0.7}
====================================================================================

Latte compila plantillas en código PHP. Por supuesto, se asegura de que el código generado es sintácticamente válido. Sin embargo, cuando se usan extensiones de terceros o RawPhpExtension, Latte no puede garantizar la corrección del fichero generado.
Además, en PHP, puede escribir código que sea sintácticamente correcto pero que esté prohibido (por ejemplo, asignar un valor a la variable $this) y cause un Error de Compilación PHP.
Si escribe una operación de este tipo en una plantilla, también se incluirá en el código PHP generado. Dado que existen más de doscientas operaciones prohibidas diferentes en PHP, Latte no pretende detectarlas. El propio PHP las marcará al renderizar, lo que normalmente no es un problema.

Sin embargo, hay situaciones en las que se desea saber durante la compilación de la plantilla que no contiene errores de compilación de PHP. Especialmente cuando las plantillas pueden ser editadas por usuarios, o usted usa [Sandbox |Sandbox]. En tal caso, haga que las plantillas se comprueben durante la compilación.
Puede activar esta funcionalidad usando el método Engine::enablePhpLint(). Ya que necesita llamar al binario PHP para la comprobación, pase su ruta como parámetro:

```php
$latte = new Latte\Engine;
$latte->enablePhpLinter('/path/to/php');

try {
	$latte->compile('home.latte');
} catch (Latte\CompileException $e) {
	// atrapa errores Latte y también Compile Error en PHP
	echo 'Error: ' . $e->getMessage();
}
```


Modo estricto .[#toc-strict-mode]{data-version:3.0.8}
=====================================================

En el modo de análisis sintáctico estricto, Latte comprueba si faltan etiquetas HTML de cierre y también desactiva el uso de la variable `$this`. Para activarlo

```php
$latte = new Latte\Engine;
$latte->setStrictParsing();
```

Para generar plantillas con la cabecera `declare(strict_types=1)`, haga lo siguiente:

```php
$latte = new Latte\Engine;
$latte->setStrictTypes();
```


Traducción en plantillas .{toc: TranslatorExtension}
====================================================

Utilice la extensión `TranslatorExtension` para añadir [`{_...}` |tags#_], [`{translate}` |tags#translate] y filtrar [`translate` |filters#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:

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

	public function translate(string $original): string
	{
		// crear $traducido a partir de $original según $this->lang
		return $translated;
	}
}

$translator = new MyTranslator($lang);
$extension = new Latte\Essential\TranslatorExtension(
	$translator->translate(...), // [$translator, 'translate'] en 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:

```php
$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`:

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


Depuración y Tracy .[#toc-debugging-and-tracy]
==============================================

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

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

```php
// activa Tracy
Tracy\Debugger::enable();

$latte = new Latte\Engine;
// activa la extensión de Tracy
$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 |https://github.com/nette/tracy/releases/tag/v2.9.0]).
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:

[* latte-debugging.webp *]

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 .{toc: Linter}
============================================================

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

```shell
vendor/bin/latte-lint <path>
```

Utilice el parámetro `--strict` para activar el modo [estricto|#strict mode].

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

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

// introduzca la ruta real al archivo autoload.php
require __DIR__ . '/vendor/autoload.php';

$path = $argv[1] ?? '.';

$linter = new Latte\Tools\Linter;
$latte = $linter->getEngine();
// añada aquí sus extensiones individuales
$latte->addExtension(/* ... */);

$ok = $linter->scanDirectory($path);
exit($ok ? 0 : 1);
```

Alternativamente, puede pasar su propio objeto `Latte\Engine` al Linter:

```php
$latte = new Latte\Engine;
// aquí configuramos el objeto $latte
$linter = new Latte\Tools\Linter(engine: $latte);
```


Carga de plantillas desde una cadena .[#toc-loading-templates-from-a-string]
============================================================================

¿Necesita cargar plantillas a partir de cadenas en lugar de archivos, quizás con fines de prueba? [StringLoader |extending-latte#stringloader] le ayudará:

```php
$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 .[#toc-exception-handler]
==================================================

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

```php
$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 .[#toc-automatic-layout-lookup]
==============================================================

Mediante la etiqueta [`{layout}` |template-inheritance#layout-inheritance] 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:

```php
$finder = function (Latte\Runtime\Template $template) {
	if (!$template->getReferenceType()) {
		// devuelve la ruta al archivo de plantilla padre
		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}`.

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

Cómo renderizar una plantilla

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

$latte = new Latte\Engine;
// directorio caché
$latte->setTempDirectory('/path/to/tempdir');

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

// renderizar a la salida
$latte->render('template.latte', $params);
// o renderizar a 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,
));

Deshabilitando Auto-Escaping de Variable

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 ...}. Puede utilizarla para insertar cualquier código PHP. No está sujeta a ninguna regla del modo sandbox, por lo que su uso es responsabilidad del autor de la plantilla.

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

Comprobación del código generado

Latte compila plantillas en código PHP. Por supuesto, se asegura de que el código generado es sintácticamente válido. Sin embargo, cuando se usan extensiones de terceros o RawPhpExtension, Latte no puede garantizar la corrección del fichero generado. Además, en PHP, puede escribir código que sea sintácticamente correcto pero que esté prohibido (por ejemplo, asignar un valor a la variable $this) y cause un Error de Compilación PHP. Si escribe una operación de este tipo en una plantilla, también se incluirá en el código PHP generado. Dado que existen más de doscientas operaciones prohibidas diferentes en PHP, Latte no pretende detectarlas. El propio PHP las marcará al renderizar, lo que normalmente no es un problema.

Sin embargo, hay situaciones en las que se desea saber durante la compilación de la plantilla que no contiene errores de compilación de PHP. Especialmente cuando las plantillas pueden ser editadas por usuarios, o usted usa Sandbox. En tal caso, haga que las plantillas se comprueben durante la compilación. Puede activar esta funcionalidad usando el método Engine::enablePhpLint(). Ya que necesita llamar al binario PHP para la comprobación, pase su ruta como parámetro:

$latte = new Latte\Engine;
$latte->enablePhpLinter('/path/to/php');

try {
	$latte->compile('home.latte');
} catch (Latte\CompileException $e) {
	// atrapa errores Latte y también Compile Error en PHP
	echo 'Error: ' . $e->getMessage();
}

Modo estricto

En el modo de análisis sintáctico estricto, Latte comprueba si faltan etiquetas HTML de cierre y también desactiva el uso de la variable $this. Para activarlo

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

Para generar plantillas con la cabecera declare(strict_types=1), haga lo siguiente:

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

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
	{
		// crear $traducido a partir de $original según $this->lang
		return $translated;
	}
}

$translator = new MyTranslator($lang);
$extension = new Latte\Essential\TranslatorExtension(
	$translator->translate(...), // [$translator, 'translate'] en 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:

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

$latte = new Latte\Engine;
// activa la extensión de Tracy
$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>

Utilice el parámetro --strict para activar el modo estricto.

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

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

// introduzca la ruta real al archivo autoload.php
require __DIR__ . '/vendor/autoload.php';

$path = $argv[1] ?? '.';

$linter = new Latte\Tools\Linter;
$latte = $linter->getEngine();
// añada aquí sus extensiones individuales
$latte->addExtension(/* ... */);

$ok = $linter->scanDirectory($path);
exit($ok ? 0 : 1);

Alternativamente, puede pasar su propio objeto Latte\Engine al Linter:

$latte = new Latte\Engine;
// aquí configuramos el objeto $latte
$linter = new Latte\Tools\Linter(engine: $latte);

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()) {
		// devuelve la ruta al archivo de plantilla padre
		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}.