Nette Documentation Preview

syntax
Pratiche per gli sviluppatori
*****************************


Installazione
=============

Il modo migliore di installare Latte è con Composer:

```shell
composer require latte/latte
```

Versioni di PHP supportate (vale per le ultime versioni patch di Latte):

| versione        | compatibile con PHP
|-----------------|-------------------
| Latte 3.1       | PHP 8.2 - 8.5
| Latte 3.0       | PHP 8.0 - 8.5


Come fare il rendering di un template
=====================================

Come si fa il rendering di un template? Basta questo semplice codice:

```php
$latte = new Latte\Engine;
// directory della cache
$latte->setCacheDirectory('/path/to/tempdir');

$params = [ /* variabili del template */ ];
// oppure $params = new TemplateParameters(/* ... */);

// rendering sull'output
$latte->render('template.latte', $params);
// oppure rendering in una variabile
$output = $latte->renderToString('template.latte', $params);
```

I parametri possono essere array o, meglio ancora, un [oggetto |#I parametri come classe], che offre il controllo dei tipi e i suggerimenti nell'editor.

.[note]
Trovate esempi d'uso anche nel repository [Latte examples |https://github.com/nette-examples/latte].


Prestazioni e caching
=====================

I template Latte sono estremamente veloci, perché Latte li compila direttamente in codice PHP e li salva in una cache su disco. Non hanno quindi alcun sovraccarico rispetto ai template scritti in puro PHP.

La cache viene rigenerata automaticamente a ogni modifica del file sorgente. Durante lo sviluppo potete quindi modificare comodamente i vostri template Latte e vedere subito le modifiche nel browser. In ambiente di produzione potete disattivare questa funzionalità e guadagnare un po' di prestazioni:

```php
$latte->setAutoRefresh(false);
```

Dopo il rilascio su un server di produzione, la generazione iniziale della cache può richiedere un po' di tempo, comprensibilmente, soprattutto nelle applicazioni più grandi. Latte ha una protezione integrata contro il "cache stampede":https://en.wikipedia.org/wiki/Cache_stampede. È la situazione in cui il server riceve un gran numero di richieste contemporanee e, poiché la cache di Latte non esiste ancora, tutte la genererebbero nello stesso momento, facendo schizzare in alto l'uso della CPU. Latte è furbo: in presenza di più richieste contemporanee solo il primo thread genera la cache, gli altri aspettano e poi la usano.

Potete anche pregenerare la cache durante il rilascio (per esempio in uno script di deploy) con il metodo `Engine::warmupCache()`. Compila in anticipo il template indicato nella cache, così il primo visitatore non deve aspettare: `$latte->warmupCache('template.latte')`.


Modi per estendere Latte
========================

Latte si può personalizzare in diversi modi, dai semplici helper a costrutti del linguaggio completamente nuovi. La pagina [estendere Latte |extending-latte] li tratta in dettaglio; qui una rapida panoramica:

- **[Filtri personalizzati|custom-filters]:** per formattare o trasformare i dati nell'output del template (per esempio `{$var|myFilter}`).
- **[Funzioni personalizzate|custom-functions]:** per la logica personalizzata che richiamate nelle espressioni del template (per esempio `{myFunction($arg)}`).
- **[Tag personalizzati|custom-tags]:** per costrutti del linguaggio completamente nuovi (`{mytag}...{/mytag}` oppure `n:mytag`).
- **[Compiler pass|compiler-passes]:** funzioni che modificano l'AST del template tra l'analisi e la generazione del codice PHP (per esempio ottimizzazioni o controlli di sicurezza).
- **[Loader personalizzati|loaders]:** per cambiare il modo in cui Latte individua e carica i file dei template.

Se volete riutilizzare le vostre estensioni in più progetti o condividerle con altri, raccoglietele in una classe [Extension di Latte |extending-latte#Estensione di Latte].


I parametri come classe
=======================

Meglio che passare le variabili al template come array è creare una classe. Ottenete una [notazione con tipi sicuri|type-system], [buoni suggerimenti nell'IDE |recipes#Editor e IDE] e un modo per [registrare filtri |custom-filters#Filtri tramite una classe] e [funzioni |custom-functions#Funzioni tramite una classe].

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


Disattivare l'escaping automatico di una variabile
==================================================

Se la variabile contiene una stringa HTML, potete contrassegnarla in modo che Latte non ne esegua automaticamente (e quindi doppiamente) l'escaping. Così evitate di dover indicare `|noescape` nel template.

Il modo più semplice è racchiudere la stringa in un oggetto `Latte\Runtime\Html`:

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

Latte non esegue l'escaping nemmeno di tutti gli oggetti che implementano l'interfaccia `Latte\Runtime\HtmlStringable`. Potete quindi creare una vostra classe il cui metodo `__toString()` restituisca codice HTML di cui non verrà eseguito automaticamente l'escaping:

```php
class Emphasis implements Latte\Runtime\HtmlStringable
{
	public function __construct(
		private string $str,
	) {
	}

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

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

.[warning]
Il metodo `__toString` deve restituire HTML corretto e occuparsi dell'escaping dei parametri, altrimenti può nascere una vulnerabilità XSS!


Come estendere Latte con filtri, tag ecc.
=========================================

Come si aggiunge a Latte un filtro, una funzione, un tag personalizzati? Lo scoprite nel capitolo [estendere Latte|extending-latte]. Se volete riutilizzare le vostre modifiche in progetti diversi o condividerle con altri, conviene [creare un'estensione |extending-latte#Estensione di Latte].


Codice qualsiasi nel template `{php ...}` .{toc: RawPhpExtension}
==================================================================

Dentro il tag [`{do}` |tags#{do}] si possono scrivere solo espressioni PHP, quindi non potete inserire, per esempio, costrutti come `if ... else` o istruzioni terminate dal punto e virgola.

Potete però registrare l'estensione `RawPhpExtension`, che aggiunge il tag `{php ...}`. Con esso potete inserire qualsiasi codice PHP. Non è soggetto ad alcuna regola della modalità sandbox, quindi il suo uso è responsabilità dell'autore del template.

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


Controllo del codice generato .{data-version:3.0.7}
===================================================

Latte compila i template in codice PHP e naturalmente si assicura che il codice generato sia sintatticamente valido. Usando estensioni di terzi o `RawPhpExtension`, però, Latte non può garantire la correttezza del file generato. In PHP, inoltre, si può scrivere codice sintatticamente corretto ma vietato (per esempio assegnare un valore alla variabile `$this`), che provoca un PHP Compile Error. Se scrivete un'operazione del genere in un template, finirà anche nel codice PHP generato. Poiché in PHP le operazioni vietate diverse sono oltre duecento, Latte non punta a rilevarle: le segnalerà PHP stesso al momento del rendering, il che di solito non è un problema.

Ci sono però situazioni in cui volete sapere già durante la compilazione del template che non contiene PHP Compile Error. Soprattutto quando i template possono essere modificati dagli utenti oppure usate la [Sandbox |sandbox]. In tal caso fate controllare i template durante la compilazione. Potete attivare questa funzionalità con il metodo `Engine::enablePhpLinter()`. Poiché per il controllo deve chiamare il binario di PHP, passatene il percorso come parametro:

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

try {
	$latte->compile('home.latte');
} catch (Latte\CompileException $e) {
	// intercetta gli errori di Latte e anche i Compile Error di PHP
	echo 'Errore: ' . $e->getMessage();
}
```


Impostazioni locali .{data-version:3.0.18}
==========================================

Latte permette di impostare il locale, che influisce sulla formattazione dei numeri, delle date e sull'ordinamento. Si imposta con il metodo `setLocale()`. L'identificatore del locale segue lo standard IETF language tag usato dall'estensione PHP `intl`. È composto dal codice della lingua ed eventualmente dal codice del paese, per esempio `en_US` per l'inglese negli Stati Uniti, `de_DE` per il tedesco in Germania e così via.

```php
$latte = new Latte\Engine;
$latte->setLocale('en_US');
```

L'impostazione del locale influisce sui filtri [localDate |filters#localDate], [sort |filters#sort], [number |filters#number] e [bytes |filters#bytes].

.[note]
Richiede l'estensione PHP `intl`. L'impostazione in Latte non influisce sull'impostazione globale del locale in PHP.


Modalità rigorosa .{data-version:3.0.8}
=======================================

Nella modalità di analisi rigorosa Latte controlla che non manchino i tag HTML di chiusura e disattiva inoltre l'uso della variabile `$this`. Per attivarla:

```php
$latte = new Latte\Engine;
$latte->setFeature(Latte\Feature::StrictParsing);
```

Per generare i template con l'intestazione `declare(strict_types=1)`, procedete così:

```php
$latte = new Latte\Engine;
$latte->setFeature(Latte\Feature::StrictTypes);
```

.[note]
Da Latte 3.1 i tipi stretti sono attivi per impostazione predefinita. Potete disattivarli con `$latte->setFeature(Latte\Feature::StrictTypes, false)`.


Avvisi di migrazione .{data-version:3.1.0}
==========================================

Latte 3.1 cambia il comportamento di alcuni [attributi HTML|html-attributes]. Per esempio i valori `null` ora eliminano l'attributo invece di stampare una stringa vuota. Per trovare facilmente i punti in cui questa modifica riguarda i vostri template, potete attivare gli avvisi di migrazione:

```php
$latte->setFeature(Latte\Feature::MigrationWarnings);
```

Una volta attivi, Latte controlla gli attributi stampati ed emette un avviso utente (`E_USER_WARNING`) se l'output differisce da quello che avrebbe prodotto Latte 3.0. Quando incontrate un avviso, applicate una di queste soluzioni:

1. Se il nuovo output è quello giusto per il vostro caso d'uso (per esempio preferite che l'attributo sparisca quando è `null`), silenziate l'avviso aggiungendo il filtro `|accept`
2. Se volete che l'attributo venga stampato vuoto (per esempio `title=""`) invece di essere eliminato quando la variabile è `null`, indicate una stringa vuota come ripiego: `title={$val ?? ''}`
3. Se avete assolutamente bisogno del vecchio comportamento (per esempio la stampa di `"1"` per `true` invece di `"true"`), convertite esplicitamente il valore in stringa: `data-foo={(string) $val}`

Una volta risolti tutti gli avvisi, disattivate gli avvisi di migrazione e **rimuovete tutti** i filtri `|accept` dai vostri template, perché non servono più.


Variabili di ciclo con ambito .{data-version:3.1.3}
===================================================

Per impostazione predefinita le variabili definite in un ciclo `{foreach}` (come `$key` e `$value`) restano accessibili anche dopo la fine del ciclo, esattamente come in PHP. Questo può portare a sovrascritture involontarie quando una variabile del ciclo ha lo stesso nome di una variabile già presente nel template.

La funzionalità `ScopedLoopVariables` limita l'ambito delle variabili del ciclo al corpo del ciclo stesso. Alla fine del ciclo viene ripristinato il valore originale della variabile (se esisteva prima), oppure la variabile viene eliminata:

```php
$latte = new Latte\Engine;
$latte->setFeature(Latte\Feature::ScopedLoopVariables);
```

Esempio della differenza:

```latte
{var $item = 'original'}
{foreach [1, 2] as $item}{$item}, {/foreach}
{$item}
```

Senza `ScopedLoopVariables`: stampa `1, 2, 2` (la variabile viene sovrascritta)
Con `ScopedLoopVariables`: stampa `1, 2, original` (la variabile viene ripristinata)

Funziona anche con la sintassi di destrutturazione, per esempio `{foreach $array as [$a, $b]}`.

.[note]
Le variabili di ciclo che usano i riferimenti (`{foreach $array as &$value}`) o l'assegnazione a proprietà (`{foreach $array as $obj->prop}`) non hanno un ambito limitato, perché ciò ne vanificherebbe lo scopo.


Rimozione automatica dell'indentazione .{toc: Dedent}{data-version:3.1.3}
==========================================================================

Usando tag di tipo pari come `{if}`, `{foreach}` o `{block}` capita spesso di indentare il contenuto annidato per renderlo leggibile. Per impostazione predefinita, però, questa indentazione finisce nell'output generato. La funzionalità `Dedent` la rimuove automaticamente, così l'output resta pulito indipendentemente da quanto annidate i vostri tag Latte:

```php
$latte = new Latte\Engine;
$latte->setFeature(Latte\Feature::Dedent);
```

Esempio:

```latte
{if true}
	Hello
	World
{/if}
```

Senza `Dedent` l'output conterrebbe l'indentazione (`\tHello\n\tWorld\n`). Con `Dedent` l'indentazione viene rimossa e l'output è `Hello\nWorld\n`.

L'indentazione più profonda all'interno di un blocco viene conservata rispetto all'indentazione di base:

```latte
{if true}
	Hello
		Indented
{/if}
```

Output: `Hello\n\tIndented\n`.

L'indentazione all'interno di un blocco deve essere coerente (o tabulazioni o spazi). Se sono mischiati, Latte solleva un'eccezione `Inconsistent indentation`.


Traduzione nei template .{toc: TranslatorExtension}
====================================================

Usate l'estensione `TranslatorExtension` per aggiungere al template [`{_...}` |tags#], [`{translate}` |tags#{translate}] e il filtro [`translate` |filters#translate]. Servono a tradurre valori o parti del template in altre lingue. Il parametro è il callable che esegue la traduzione, oppure un oggetto di tipo `Nette\Localization\Translator` (passate `null` per disattivare le traduzioni):

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

	public function translate(string $original): string
	{
		// crea $translated da $original in base a $this->lang
		return $translated;
	}
}

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

Il traduttore viene chiamato in fase di esecuzione, durante il rendering del template. Latte è però in grado di tradurre tutti i testi statici già durante la compilazione del template. Questo fa risparmiare prestazioni, perché ogni stringa viene tradotta una sola volta e la traduzione risultante viene scritta nel file compilato. Nella directory della cache nascono così più versioni compilate del template, una per ogni lingua. Per ottenerlo basta indicare la lingua come secondo parametro:

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

Per testo statico intendiamo, per esempio, `{_'hello'}` oppure `{translate}hello{/translate}`. Il testo non statico, come `{_$foo}`, continuerà a essere tradotto in fase di esecuzione.

Il template può passare al traduttore anche parametri aggiuntivi, con `{_$original, foo: bar}` o `{translate foo: bar}`, che esso riceve nell'array `$params`:

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


Debugging e Tracy
=================

Latte cerca di rendere lo sviluppo il più piacevole possibile. Per il debugging esistono tre tag: [`{dump}` |tags#{dump}], [`{debugbreak}` |tags#{debugbreak}] e [`{trace}` |tags#{trace}].

Il massimo della comodità la otterrete installando l'eccellente [strumento di debug Tracy|tracy:] e attivando il plugin per Latte:

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

$latte = new Latte\Engine;
// attiva l'estensione di Tracy
$latte->addExtension(new Latte\Bridges\Tracy\TracyExtension);
```

Ora vedrete tutti gli errori in un'elegante schermata rossa, compresi gli errori nei template con l'evidenziazione di riga e colonna ([video|https://github.com/nette/tracy/releases/tag/v2.9.0]). Allo stesso tempo, nell'angolo in basso a destra, nella cosiddetta Tracy Bar, compare una scheda per Latte, dove vedete chiaramente tutti i template renderizzati e le loro relazioni (con la possibilità di entrare nel template o nel codice compilato con un clic), oltre alle variabili:

[* latte-debugging.webp *]

Poiché Latte compila i template in codice PHP leggibile, potete comodamente eseguirli passo passo nel vostro IDE.


Linter: verifica della sintassi dei template .{toc: Linter}
============================================================

Lo strumento **Linter** serve a verificare tutti i template. Il suo scopo è esaminare i file indicati e assicurarsi che non contengano errori di sintassi né riferimenti a tag, filtri, funzioni, classi o costrutti simili inesistenti.

Il Linter si esegue dalla riga di comando:

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

Usate il parametro `--strict` per attivare la [modalità rigorosa |#Modalità rigorosa]. Il parametro `--debug` stampa il nome di ogni file elaborato e i dettagli completi delle eccezioni, il che aiuta nella ricerca dei problemi.

Se usate tag, filtri o altre estensioni di Latte personalizzati, dovete creare una vostra variante del Linter, per esempio `custom-latte-lint`. In questo script registrate tutte le estensioni necessarie prima che avvenga la verifica vera e propria dei template:

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

// indicate il percorso reale del file autoload.php
require __DIR__ . '/vendor/autoload.php';

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

$linter = new Latte\Tools\Linter;
$latte = $linter->getEngine();
// aggiungete qui le vostre singole estensioni
$latte->addExtension(/* ... */);

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

In alternativa potete passare al Linter un vostro oggetto `Latte\Engine`:

```php
$latte = new Latte\Engine;
// qui configuriamo l'oggetto $latte
$linter = new Latte\Tools\Linter(engine: $latte);
```

Il linter personalizzato che ne risulta si usa poi esattamente come lo strumento standard, ma con la piena conoscenza di tutte le vostre estensioni.


Caricare i template da una stringa
==================================

Vi serve caricare i template da stringhe invece che da file, magari per i test? Vi aiuta [StringLoader |loaders#StringLoader]:

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

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


Gestore di eccezioni
====================

Potete definire un vostro gestore per le eccezioni attese. Gli vengono passate le eccezioni sollevate dentro [`{try}` |tags#{try}] e nella [sandbox |sandbox].

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

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


Ricerca automatica del layout
=============================

Con il tag [`{layout}` |template-inheritance#Ereditarietà del layout] il template stabilisce qual è il suo template genitore. È anche possibile far cercare il layout automaticamente, il che semplifica la scrittura dei template, perché non dovranno contenere il tag `{layout}`.

Lo si ottiene così:

```php
// restituisce il percorso del file del template genitore
$finder = fn(Latte\Runtime\Template $template) => 'automatic.layout.latte';
$latte = new Latte\Engine;
$latte->addProvider('coreParentFinder', $finder);
```

Se il template non deve avere un layout, lo segnalerà con il tag `{layout none}`.

Pratiche per gli sviluppatori

Installazione

Il modo migliore di installare Latte è con Composer:

composer require latte/latte

Versioni di PHP supportate (vale per le ultime versioni patch di Latte):

versione compatibile con PHP
Latte 3.1 PHP 8.2 – 8.5
Latte 3.0 PHP 8.0 – 8.5

Come fare il rendering di un template

Come si fa il rendering di un template? Basta questo semplice codice:

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

$params = [ /* variabili del template */ ];
// oppure $params = new TemplateParameters(/* ... */);

// rendering sull'output
$latte->render('template.latte', $params);
// oppure rendering in una variabile
$output = $latte->renderToString('template.latte', $params);

I parametri possono essere array o, meglio ancora, un oggetto, che offre il controllo dei tipi e i suggerimenti nell'editor.

Trovate esempi d'uso anche nel repository Latte examples.

Prestazioni e caching

I template Latte sono estremamente veloci, perché Latte li compila direttamente in codice PHP e li salva in una cache su disco. Non hanno quindi alcun sovraccarico rispetto ai template scritti in puro PHP.

La cache viene rigenerata automaticamente a ogni modifica del file sorgente. Durante lo sviluppo potete quindi modificare comodamente i vostri template Latte e vedere subito le modifiche nel browser. In ambiente di produzione potete disattivare questa funzionalità e guadagnare un po' di prestazioni:

$latte->setAutoRefresh(false);

Dopo il rilascio su un server di produzione, la generazione iniziale della cache può richiedere un po' di tempo, comprensibilmente, soprattutto nelle applicazioni più grandi. Latte ha una protezione integrata contro il cache stampede. È la situazione in cui il server riceve un gran numero di richieste contemporanee e, poiché la cache di Latte non esiste ancora, tutte la genererebbero nello stesso momento, facendo schizzare in alto l'uso della CPU. Latte è furbo: in presenza di più richieste contemporanee solo il primo thread genera la cache, gli altri aspettano e poi la usano.

Potete anche pregenerare la cache durante il rilascio (per esempio in uno script di deploy) con il metodo Engine::warmupCache(). Compila in anticipo il template indicato nella cache, così il primo visitatore non deve aspettare: $latte->warmupCache('template.latte').

Modi per estendere Latte

Latte si può personalizzare in diversi modi, dai semplici helper a costrutti del linguaggio completamente nuovi. La pagina estendere Latte li tratta in dettaglio; qui una rapida panoramica:

  • Filtri personalizzati: per formattare o trasformare i dati nell'output del template (per esempio {$var|myFilter}).
  • Funzioni personalizzate: per la logica personalizzata che richiamate nelle espressioni del template (per esempio {myFunction($arg)}).
  • Tag personalizzati: per costrutti del linguaggio completamente nuovi ({mytag}...{/mytag} oppure n:mytag).
  • Compiler pass: funzioni che modificano l'AST del template tra l'analisi e la generazione del codice PHP (per esempio ottimizzazioni o controlli di sicurezza).
  • Loader personalizzati: per cambiare il modo in cui Latte individua e carica i file dei template.

Se volete riutilizzare le vostre estensioni in più progetti o condividerle con altri, raccoglietele in una classe Extension di Latte.

I parametri come classe

Meglio che passare le variabili al template come array è creare una classe. Ottenete una notazione con tipi sicuri, buoni suggerimenti nell'IDE e un modo per registrare filtri e funzioni.

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

Disattivare l'escaping automatico di una variabile

Se la variabile contiene una stringa HTML, potete contrassegnarla in modo che Latte non ne esegua automaticamente (e quindi doppiamente) l'escaping. Così evitate di dover indicare |noescape nel template.

Il modo più semplice è racchiudere la stringa in un oggetto Latte\Runtime\Html:

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

Latte non esegue l'escaping nemmeno di tutti gli oggetti che implementano l'interfaccia Latte\Runtime\HtmlStringable. Potete quindi creare una vostra classe il cui metodo __toString() restituisca codice HTML di cui non verrà eseguito automaticamente l'escaping:

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

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

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

Il metodo __toString deve restituire HTML corretto e occuparsi dell'escaping dei parametri, altrimenti può nascere una vulnerabilità XSS!

Come estendere Latte con filtri, tag ecc.

Come si aggiunge a Latte un filtro, una funzione, un tag personalizzati? Lo scoprite nel capitolo estendere Latte. Se volete riutilizzare le vostre modifiche in progetti diversi o condividerle con altri, conviene creare un'estensione.

Codice qualsiasi nel template {php ...}

Dentro il tag {do} si possono scrivere solo espressioni PHP, quindi non potete inserire, per esempio, costrutti come if ... else o istruzioni terminate dal punto e virgola.

Potete però registrare l'estensione RawPhpExtension, che aggiunge il tag {php ...}. Con esso potete inserire qualsiasi codice PHP. Non è soggetto ad alcuna regola della modalità sandbox, quindi il suo uso è responsabilità dell'autore del template.

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

Controllo del codice generato

Latte compila i template in codice PHP e naturalmente si assicura che il codice generato sia sintatticamente valido. Usando estensioni di terzi o RawPhpExtension, però, Latte non può garantire la correttezza del file generato. In PHP, inoltre, si può scrivere codice sintatticamente corretto ma vietato (per esempio assegnare un valore alla variabile $this), che provoca un PHP Compile Error. Se scrivete un'operazione del genere in un template, finirà anche nel codice PHP generato. Poiché in PHP le operazioni vietate diverse sono oltre duecento, Latte non punta a rilevarle: le segnalerà PHP stesso al momento del rendering, il che di solito non è un problema.

Ci sono però situazioni in cui volete sapere già durante la compilazione del template che non contiene PHP Compile Error. Soprattutto quando i template possono essere modificati dagli utenti oppure usate la Sandbox. In tal caso fate controllare i template durante la compilazione. Potete attivare questa funzionalità con il metodo Engine::enablePhpLinter(). Poiché per il controllo deve chiamare il binario di PHP, passatene il percorso come parametro:

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

try {
	$latte->compile('home.latte');
} catch (Latte\CompileException $e) {
	// intercetta gli errori di Latte e anche i Compile Error di PHP
	echo 'Errore: ' . $e->getMessage();
}

Impostazioni locali

Latte permette di impostare il locale, che influisce sulla formattazione dei numeri, delle date e sull'ordinamento. Si imposta con il metodo setLocale(). L'identificatore del locale segue lo standard IETF language tag usato dall'estensione PHP intl. È composto dal codice della lingua ed eventualmente dal codice del paese, per esempio en_US per l'inglese negli Stati Uniti, de_DE per il tedesco in Germania e così via.

$latte = new Latte\Engine;
$latte->setLocale('en_US');

L'impostazione del locale influisce sui filtri localDate, sort, number e bytes.

Richiede l'estensione PHP intl. L'impostazione in Latte non influisce sull'impostazione globale del locale in PHP.

Modalità rigorosa

Nella modalità di analisi rigorosa Latte controlla che non manchino i tag HTML di chiusura e disattiva inoltre l'uso della variabile $this. Per attivarla:

$latte = new Latte\Engine;
$latte->setFeature(Latte\Feature::StrictParsing);

Per generare i template con l'intestazione declare(strict_types=1), procedete così:

$latte = new Latte\Engine;
$latte->setFeature(Latte\Feature::StrictTypes);

Da Latte 3.1 i tipi stretti sono attivi per impostazione predefinita. Potete disattivarli con $latte->setFeature(Latte\Feature::StrictTypes, false).

Avvisi di migrazione

Latte 3.1 cambia il comportamento di alcuni attributi HTML. Per esempio i valori null ora eliminano l'attributo invece di stampare una stringa vuota. Per trovare facilmente i punti in cui questa modifica riguarda i vostri template, potete attivare gli avvisi di migrazione:

$latte->setFeature(Latte\Feature::MigrationWarnings);

Una volta attivi, Latte controlla gli attributi stampati ed emette un avviso utente (E_USER_WARNING) se l'output differisce da quello che avrebbe prodotto Latte 3.0. Quando incontrate un avviso, applicate una di queste soluzioni:

  1. Se il nuovo output è quello giusto per il vostro caso d'uso (per esempio preferite che l'attributo sparisca quando è null), silenziate l'avviso aggiungendo il filtro |accept
  2. Se volete che l'attributo venga stampato vuoto (per esempio title="") invece di essere eliminato quando la variabile è null, indicate una stringa vuota come ripiego: title={$val ?? ''}
  3. Se avete assolutamente bisogno del vecchio comportamento (per esempio la stampa di "1" per true invece di "true"), convertite esplicitamente il valore in stringa: data-foo={(string) $val}

Una volta risolti tutti gli avvisi, disattivate gli avvisi di migrazione e rimuovete tutti i filtri |accept dai vostri template, perché non servono più.

Variabili di ciclo con ambito

Per impostazione predefinita le variabili definite in un ciclo {foreach} (come $key e $value) restano accessibili anche dopo la fine del ciclo, esattamente come in PHP. Questo può portare a sovrascritture involontarie quando una variabile del ciclo ha lo stesso nome di una variabile già presente nel template.

La funzionalità ScopedLoopVariables limita l'ambito delle variabili del ciclo al corpo del ciclo stesso. Alla fine del ciclo viene ripristinato il valore originale della variabile (se esisteva prima), oppure la variabile viene eliminata:

$latte = new Latte\Engine;
$latte->setFeature(Latte\Feature::ScopedLoopVariables);

Esempio della differenza:

{var $item = 'original'}
{foreach [1, 2] as $item}{$item}, {/foreach}
{$item}

Senza ScopedLoopVariables: stampa 1, 2, 2 (la variabile viene sovrascritta) Con ScopedLoopVariables: stampa 1, 2, original (la variabile viene ripristinata)

Funziona anche con la sintassi di destrutturazione, per esempio {foreach $array as [$a, $b]}.

Le variabili di ciclo che usano i riferimenti ({foreach $array as &$value}) o l'assegnazione a proprietà ({foreach $array as $obj->prop}) non hanno un ambito limitato, perché ciò ne vanificherebbe lo scopo.

Rimozione automatica dell'indentazione

Usando tag di tipo pari come {if}, {foreach} o {block} capita spesso di indentare il contenuto annidato per renderlo leggibile. Per impostazione predefinita, però, questa indentazione finisce nell'output generato. La funzionalità Dedent la rimuove automaticamente, così l'output resta pulito indipendentemente da quanto annidate i vostri tag Latte:

$latte = new Latte\Engine;
$latte->setFeature(Latte\Feature::Dedent);

Esempio:

{if true}
	Hello
	World
{/if}

Senza Dedent l'output conterrebbe l'indentazione (\tHello\n\tWorld\n). Con Dedent l'indentazione viene rimossa e l'output è Hello\nWorld\n.

L'indentazione più profonda all'interno di un blocco viene conservata rispetto all'indentazione di base:

{if true}
	Hello
		Indented
{/if}

Output: Hello\n\tIndented\n.

L'indentazione all'interno di un blocco deve essere coerente (o tabulazioni o spazi). Se sono mischiati, Latte solleva un'eccezione Inconsistent indentation.

Traduzione nei template

Usate l'estensione TranslatorExtension per aggiungere al template {_...}, {translate} e il filtro translate. Servono a tradurre valori o parti del template in altre lingue. Il parametro è il callable che esegue la traduzione, oppure un oggetto di tipo Nette\Localization\Translator (passate null per disattivare le traduzioni):

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

	public function translate(string $original): string
	{
		// crea $translated da $original in base a $this->lang
		return $translated;
	}
}

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

Il traduttore viene chiamato in fase di esecuzione, durante il rendering del template. Latte è però in grado di tradurre tutti i testi statici già durante la compilazione del template. Questo fa risparmiare prestazioni, perché ogni stringa viene tradotta una sola volta e la traduzione risultante viene scritta nel file compilato. Nella directory della cache nascono così più versioni compilate del template, una per ogni lingua. Per ottenerlo basta indicare la lingua come secondo parametro:

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

Per testo statico intendiamo, per esempio, {_'hello'} oppure {translate}hello{/translate}. Il testo non statico, come {_$foo}, continuerà a essere tradotto in fase di esecuzione.

Il template può passare al traduttore anche parametri aggiuntivi, con {_$original, foo: bar} o {translate foo: bar}, che esso riceve nell'array $params:

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

Debugging e Tracy

Latte cerca di rendere lo sviluppo il più piacevole possibile. Per il debugging esistono tre tag: {dump}, {debugbreak} e {trace}.

Il massimo della comodità la otterrete installando l'eccellente strumento di debug Tracy e attivando il plugin per Latte:

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

$latte = new Latte\Engine;
// attiva l'estensione di Tracy
$latte->addExtension(new Latte\Bridges\Tracy\TracyExtension);

Ora vedrete tutti gli errori in un'elegante schermata rossa, compresi gli errori nei template con l'evidenziazione di riga e colonna (video). Allo stesso tempo, nell'angolo in basso a destra, nella cosiddetta Tracy Bar, compare una scheda per Latte, dove vedete chiaramente tutti i template renderizzati e le loro relazioni (con la possibilità di entrare nel template o nel codice compilato con un clic), oltre alle variabili:

Poiché Latte compila i template in codice PHP leggibile, potete comodamente eseguirli passo passo nel vostro IDE.

Linter: verifica della sintassi dei template

Lo strumento Linter serve a verificare tutti i template. Il suo scopo è esaminare i file indicati e assicurarsi che non contengano errori di sintassi né riferimenti a tag, filtri, funzioni, classi o costrutti simili inesistenti.

Il Linter si esegue dalla riga di comando:

vendor/bin/latte-lint <path>

Usate il parametro --strict per attivare la modalità rigorosa. Il parametro --debug stampa il nome di ogni file elaborato e i dettagli completi delle eccezioni, il che aiuta nella ricerca dei problemi.

Se usate tag, filtri o altre estensioni di Latte personalizzati, dovete creare una vostra variante del Linter, per esempio custom-latte-lint. In questo script registrate tutte le estensioni necessarie prima che avvenga la verifica vera e propria dei template:

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

// indicate il percorso reale del file autoload.php
require __DIR__ . '/vendor/autoload.php';

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

$linter = new Latte\Tools\Linter;
$latte = $linter->getEngine();
// aggiungete qui le vostre singole estensioni
$latte->addExtension(/* ... */);

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

In alternativa potete passare al Linter un vostro oggetto Latte\Engine:

$latte = new Latte\Engine;
// qui configuriamo l'oggetto $latte
$linter = new Latte\Tools\Linter(engine: $latte);

Il linter personalizzato che ne risulta si usa poi esattamente come lo strumento standard, ma con la piena conoscenza di tutte le vostre estensioni.

Caricare i template da una stringa

Vi serve caricare i template da stringhe invece che da file, magari per i test? Vi aiuta StringLoader:

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

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

Gestore di eccezioni

Potete definire un vostro gestore per le eccezioni attese. Gli vengono passate le eccezioni sollevate dentro {try} e nella sandbox.

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

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

Ricerca automatica del layout

Con il tag {layout} il template stabilisce qual è il suo template genitore. È anche possibile far cercare il layout automaticamente, il che semplifica la scrittura dei template, perché non dovranno contenere il tag {layout}.

Lo si ottiene così:

// restituisce il percorso del file del template genitore
$finder = fn(Latte\Runtime\Template $template) => 'automatic.layout.latte';
$latte = new Latte\Engine;
$latte->addProvider('coreParentFinder', $finder);

Se il template non deve avere un layout, lo segnalerà con il tag {layout none}.