Pratiche per gli sviluppatori

Installazione

Il modo migliore per installare Latte è utilizzare un Composer:

composer require latte/latte

Versioni PHP supportate (si applica alle ultime versioni di Latte):

versione compatibile con PHP
Latte 3.0 PHP 8.0 – 8.2

Come renderizzare un modello

Come renderizzare un template? Basta usare questo semplice codice:

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

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

// rendere all'output
$latte->render('template.latte', $params);
// o rendere alla variabile
$output = $latte->renderToString('template.latte', $params);

I parametri possono essere array o meglio ancora oggetti, che forniranno il controllo del tipo e il suggerimento nell'editor.

Si possono trovare esempi di utilizzo nel repository Latte examples.

Prestazioni e cache

I modelli di Latte sono estremamente veloci, perché Latte li compila direttamente in codice PHP e li memorizza su disco. Pertanto, non hanno alcun sovraccarico rispetto ai modelli scritti in PHP puro.

La cache viene rigenerata automaticamente ogni volta che si modifica il file sorgente. È quindi possibile modificare comodamente i modelli Latte durante lo sviluppo e vedere immediatamente le modifiche nel browser. È possibile disabilitare questa funzione in un ambiente di produzione e risparmiare un po' di prestazioni:

$latte->setAutoRefresh(false);

Quando viene distribuito su un server di produzione, la generazione iniziale della cache, soprattutto per le applicazioni più grandi, può comprensibilmente richiedere un po' di tempo. Latte ha una prevenzione integrata contro il cache stampede. Si tratta di una situazione in cui il server riceve un gran numero di richieste simultanee e, poiché la cache di Latte non esiste ancora, tutte le richieste vengono generate contemporaneamente. Il che fa impennare la CPU. Latte è intelligente e quando ci sono più richieste simultanee, solo il primo thread genera la cache, gli altri aspettano e poi la usano.

Parametri come classe

Meglio che passare le variabili al template come array è creare una classe. Si ottiene una notazione sicura per il tipo, un buon suggerimento 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,
));

Disabilitare la cancellazione automatica di una variabile

Se la variabile contiene una stringa HTML, è possibile contrassegnarla in modo che Latte non esegua automaticamente (e quindi doppiamente) l'escape. Questo evita la necessità di specificare |noescape nel modello.

Il modo più semplice è avvolgere 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. È quindi possibile creare una propria classe il cui metodo __toString() restituirà un codice HTML che non sarà sottoposto a escape automatico:

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 un codice HTML corretto e fornire l'escape dei parametri, altrimenti si potrebbe verificare una vulnerabilità XSS!

Come estendere Latte con filtri, tag, ecc.

Come aggiungere a Latte un filtro, una funzione, un tag, ecc. personalizzati? Scopritelo nel capitolo Estensione di Latte. Se volete riutilizzare le vostre modifiche in progetti diversi o se volete condividerle con altri, dovete creare un'estensione.

Qualsiasi codice nel modello {php ...}

Solo le espressioni PHP possono essere scritte all'interno del tag {do} quindi non è possibile, ad esempio, inserire costrutti come if ... else o dichiarazioni terminate con punto e virgola.

Tuttavia, è possibile registrare l'estensione RawPhpExtension, che aggiunge il tag {php ...}. Si può usare per inserire qualsiasi codice PHP. Non è soggetta a nessuna regola della modalità sandbox, quindi l'uso è responsabilità dell'autore del template.

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

Verifica del codice generato

Latte compila i modelli in codice PHP. Naturalmente, garantisce che il codice generato sia sintatticamente valido. Tuttavia, quando si usano estensioni di terze parti o RawPhpExtension, Latte non può garantire la correttezza del file generato. Inoltre, in PHP è possibile scrivere codice sintatticamente corretto ma vietato (ad esempio, assegnare un valore alla variabile $this) e causare un errore di compilazione PHP. Se si scrive un'operazione di questo tipo in un template, verrà inclusa anche nel codice PHP generato. Poiché esistono oltre duecento diverse operazioni proibite in PHP, Latte non ha lo scopo di rilevarle. Il PHP stesso le segnala al momento del rendering, il che di solito non è un problema.

Tuttavia, ci sono situazioni in cui si vuole sapere durante la compilazione del template che non contiene errori di compilazione PHP. Soprattutto quando i template possono essere modificati dagli utenti o si usa Sandbox. In tal caso, è opportuno controllare i template durante la compilazione. È possibile attivare questa funzionalità utilizzando il metodo Engine::enablePhpLint(). Poiché deve richiamare il binario PHP per il controllo, passare il suo percorso come parametro:

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

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

Modalità rigorosa

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

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

Per generare modelli con l'intestazione declare(strict_types=1), procedete come segue:

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

Traduzione nei template

Utilizzare l'estensione TranslatorExtension per aggiungere {_...}, {translate} e il filtro translate al template. Sono usati per tradurre valori o parti del template in altre lingue. Il parametro è il metodo (callable PHP) che esegue la traduzione:

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

	public function translate(string $original): string
	{
		// crea $tradotto da $originale 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 quando il template viene reso. Tuttavia, Latte può tradurre tutti i testi statici durante la compilazione del template. Ciò consente di risparmiare sulle prestazioni, perché ogni stringa viene tradotta una sola volta e la traduzione risultante viene scritta nel file compilato. In questo modo si creano più versioni compilate del modello nella cartella cache, una per ogni lingua. Per farlo, è sufficiente 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}. Il testo non statico, come {_$foo}, continuerà a essere tradotto in fase di esecuzione.

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

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

Debug e Tracy

Latte cerca di rendere lo sviluppo il più piacevole possibile. Per il debug, sono disponibili tre tag {dump}, {debugbreak} e {trace}.

Il massimo del comfort si ottiene installando l'ottimo strumento di debug Tracy e attivando il plugin Latte:

// abilita 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'ordinata schermata rossa, compresi gli errori nei modelli con evidenziazione di righe e colonne (video). Allo stesso tempo, nell'angolo in basso a destra della cosiddetta barra di Tracy, appare una scheda per Latte, dove si possono vedere chiaramente tutti i modelli renderizzati e le loro relazioni (compresa la possibilità di fare clic nel modello o nel codice compilato), nonché le variabili:

Dal momento che Latte compila i template in codice PHP leggibile, si può comodamente passare attraverso di essi nel proprio IDE.

Linter: Convalidare la sintassi dei template

Lo strumento Linter aiuta a esaminare tutti i template e a verificare la presenza di errori di sintassi. Viene lanciato dalla console:

vendor/bin/latte-lint <path>

Utilizzare il parametro --strict per attivare la modalità strict.

Se si usano tag personalizzati, creare anche un Linter personalizzato, ad esempio custom-latte-lint:

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

// inserire il percorso effettivo del file autoload.php
require __DIR__ . '/vendor/autoload.php';

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

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

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

In alternativa, è possibile passare il proprio oggetto Latte\Engine a Linter:

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

Caricare modelli da una stringa

Avete bisogno di caricare modelli da stringhe invece che da file, magari a scopo 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);

Gestore delle eccezioni

È possibile definire un proprio gestore per le eccezioni previste. Le eccezioni sollevate all'interno di {try} e nella sandbox vengono passate ad esso.

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

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

Ricerca automatica del layout

Utilizzando il tag {layout} il template determina il suo template padre. È anche possibile fare in modo che il layout venga cercato automaticamente, il che semplificherà la scrittura dei template, poiché non dovranno includere il tag {layout}.

Questo si ottiene come segue:

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

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

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

versione: 3.0