Pratiche di Sviluppo

Installazione

Il modo migliore per installare Latte è tramite Composer:

composer require latte/latte

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

versione compatibile con PHP
Latte 3.0 PHP 8.0 – 8.2

Come Renderizzare un Template

Come renderizzare un template? Basta questo semplice codice:

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

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

// disegna sull'output
$latte->render('template.latte', $params);
// disegna nella variabile
$output = $latte->renderToString('template.latte', $params);

I parametri possono essere un array o, ancora meglio, un oggetto, che garantirà il controllo dei tipi e i suggerimenti negli editor.

Esempi di utilizzo si trovano anche nel repository Esempi di Latte.

Prestazioni e Cache

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

La cache si rigenera automaticamente ogni volta che modificate il file sorgente. Durante lo sviluppo, potete quindi modificare comodamente i template in Latte e vedere immediatamente le modifiche nel browser. Potete disabilitare questa funzione nell'ambiente di produzione per risparmiare un po' di prestazioni:

$latte->setAutoRefresh(false);

Durante il deployment su un server di produzione, la generazione iniziale della cache, specialmente per applicazioni più estese, può ovviamente richiedere un po' di tempo. Latte ha una prevenzione integrata contro la cache stampede. Si tratta di una situazione in cui un gran numero di richieste concorrenti avvia Latte e, poiché la cache non esiste ancora, tutte inizierebbero a generarla contemporaneamente. Ciò sovraccaricherebbe eccessivamente il server. Latte è intelligente e, in caso di più richieste concorrenti, solo il primo thread genera la cache, gli altri aspettano e poi la utilizzano.

Parametri come Classe

Meglio che passare le variabili al template come array è creare una classe. Otterrete così una scrittura type-safe, suggerimenti utili 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,
));

Disabilitazione dell'Auto-Escaping di una Variabile

Se una variabile contiene una stringa HTML, potete contrassegnarla in modo che Latte non la esegua automaticamente (e quindi doppiamente) l'escape. Eviterete così la necessità di specificare |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 inoltre non esegue l'escape di tutti gli oggetti che implementano l'interfaccia Latte\HtmlStringable. Potete quindi creare la vostra classe, il cui metodo __toString() restituirà codice HTML che non verrà automaticamente escapato:

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

Il metodo __toString deve restituire HTML corretto e garantire l'escaping dei parametri, altrimenti può verificarsi una vulnerabilità XSS!

Come Estendere Latte con Filtri, Tag, ecc.

Come aggiungere a Latte un filtro, una funzione, un tag personalizzato, ecc.? Questo è trattato nel capitolo estendere Latte. Se volete riutilizzare le vostre modifiche in diversi progetti o condividerle con altri, dovreste creare un'estensione.

Codice PHP Arbitrario nel Template {php ...}

All'interno del tag {do} è possibile scrivere solo espressioni PHP, non potete quindi inserire costrutti come if ... else o istruzioni terminate da punto e virgola.

Tuttavia, potete registrare l'estensione RawPhpExtension, che aggiunge il tag {php ...}. Con questo potete inserire qualsiasi codice PHP. Non si applicano ad esso regole della modalità sandbox, l'uso è quindi responsabilità dell'autore del template.

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

Controllo del Codice Generato

Latte compila i template in codice PHP. Naturalmente, si preoccupa che il codice generato sia sintatticamente valido. Tuttavia, quando si utilizzano estensioni di terze parti o RawPhpExtension, Latte non può garantire la correttezza del file generato. Inoltre, è possibile scrivere in PHP codice che, sebbene sintatticamente corretto, è vietato (ad esempio, l'assegnazione di un valore alla variabile $this) e causa un PHP Compile Error. Se scrivete tale operazione in un template, finirà anche nel codice PHP generato. Poiché in PHP esistono circa duecento diverse operazioni vietate, Latte non ha l'ambizione di rilevarle. Sarà lo stesso PHP a segnalarle durante il rendering, il che di solito non è un problema.

Ci sono però situazioni in cui volete sapere già al momento della compilazione del template che non contiene alcun PHP Compile Error. Soprattutto se i template possono essere modificati dagli utenti, o se utilizzate Sandbox. In tal caso, fate controllare i template già durante la compilazione. Questa funzionalità si attiva con il metodo Engine::enablePhpLint(). Poiché per il controllo necessita di chiamare l'eseguibile PHP, passate il percorso ad esso come parametro:

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

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

Impostazioni Regionali

Latte consente di impostare le impostazioni regionali, che influenzano la formattazione di numeri, date e l'ordinamento. Si imposta tramite il metodo setLocale(). L'identificatore delle impostazioni regionali segue lo standard IETF language tag, utilizzato dall'estensione PHP intl. È composto dal codice della lingua e opzionalmente dal codice del paese, ad es. en_US per l'inglese negli Stati Uniti, de_DE per il tedesco in Germania, it_IT per l'italiano in Italia, ecc.

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

L'impostazione delle impostazioni regionali influisce sui filtri localDate, sort, number e bytes.

Richiede l'estensione PHP intl. L'impostazione in Latte non influisce sull'impostazione globale delle impostazioni regionali in PHP.

Modalità Rigorosa

Nella modalità di parsing rigorosa, Latte controlla se mancano tag HTML di chiusura e vieta anche l'uso della variabile $this. La attivate così:

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

La generazione di template con l'header declare(strict_types=1) si attiva così:

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

Traduzione nei Template

Usando l'estensione TranslatorExtension aggiungete al template i tag {_...}, {translate} e il filtro translate. Servono per tradurre valori o parti del template in altre lingue. Come parametro specifichiamo il metodo (PHP callable) che esegue la traduzione:

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

	public function translate(string $original): string
	{
		// da $original creiamo $translated secondo $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 a runtime durante il rendering del template. Latte, tuttavia, può tradurre tutti i testi statici già durante la compilazione del template. Ciò consente di risparmiare prestazioni, poiché ogni stringa viene tradotta una sola volta e la traduzione risultante viene scritta nella forma compilata. Nella directory della cache verranno quindi create più versioni compilate del template, una per ogni lingua. Per fare ciò, basta specificare la lingua come secondo parametro:

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

Per testo statico si intende ad esempio {_'hello'} o {translate}hello{/translate}. I testi non statici, come {_$foo}, continueranno ad essere tradotti a runtime.

Al traduttore è possibile passare dal template anche parametri aggiuntivi usando {_$original, foo: bar} o {translate foo: bar}, che riceverà come 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. Direttamente per scopi di debug esistono tre tag {dump}, {debugbreak} e {trace}.

Il massimo comfort si ottiene installando anche l'eccellente strumento di debug Tracy e attivando l'add-on per Latte:

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

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

Ora tutti gli errori verranno visualizzati in una chiara schermata rossa, inclusi gli errori nei template con evidenziazione della riga e della colonna (video). Allo stesso tempo, nell'angolo in basso a destra nella cosiddetta Tracy Bar apparirà una scheda per Latte, dove sono chiaramente visibili tutti i template renderizzati e le loro relazioni reciproche (inclusa la possibilità di fare clic per passare al template o al codice compilato) e anche le variabili:

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

Linter: Validazione della Sintassi dei Template

Lo strumento Linter vi aiuta a scorrere tutti i template e a verificare che non contengano errori di sintassi. Si avvia dalla console:

vendor/bin/latte-lint <percorso>

Il parametro --strict attiva la modalità rigorosa.

Se utilizzate tag personalizzati, create anche la vostra versione di Linter, ad es. custom-latte-lint:

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

// inserisci il percorso reale al file autoload.php
require __DIR__ . '/vendor/autoload.php';

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

$linter = new Latte\Tools\Linter;
$latte = $linter->getEngine();
// aggiungi qui le tue estensioni individuali
$latte->addExtension(/* ... */);

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

In alternativa, potete passare il vostro oggetto Latte\Engine personalizzato a Linter:

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

Caricamento dei Template da Stringa

Avete bisogno di caricare template da stringhe invece che da file, ad esempio per scopi di test? StringLoader vi aiuterà:

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

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

Handler delle Eccezioni

Potete definire il vostro handler personalizzato per le eccezioni attese. Gli verranno passate le eccezioni sorte all'interno di {try} e nel 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

Usando il tag {layout} il template specifica il suo template genitore. È anche possibile far cercare il layout automaticamente, il che semplifica la scrittura dei template, poiché non sarà necessario specificare il tag {layout} in essi.

Ciò si ottiene nel seguente modo:

$finder = function (Latte\Runtime\Template $template) {
	if (!$template->getReferenceType()) {
		// restituisce il percorso al file di layout
		return 'automatic.layout.latte';
	}
};

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

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

versione: 3.0