Caricatori di modelli
I caricatori sono il meccanismo che Latte utilizza per recuperare il codice sorgente dei modelli. Normalmente i modelli sono file memorizzati su disco, ma il sistema flessibile di caricatori di Latte consente di caricarli praticamente da qualsiasi punto o addirittura di generarli dinamicamente.
Che cos'è un caricatore?
In genere, quando si lavora con i modelli, si pensa ai file di .latte
che risiedono nella struttura di directory
del progetto. Questo viene gestito dal FileLoader predefinito di Latte. Tuttavia, la connessione tra
il nome di un modello (come 'main.latte'
o 'components/card.latte'
) e il suo contenuto effettivo di
codice sorgente non deve essere una mappatura diretta del percorso del file.
È qui che entrano in gioco i caricatori. Un caricatore è un oggetto responsabile di prendere il nome di un modello (una
stringa identificativa) e di fornire a Latte il suo codice sorgente. Latte si affida interamente al caricatore configurato per
questo compito. Questo vale non solo per il modello iniziale richiesto tramite $latte->render('main.latte')
, ma
anche per ogni modello a cui si fa riferimento usando tag come {include ...}
, {layout ...}
,
{embed ...}
, o {import ...}
.
Perché usare un caricatore personalizzato?
- Recuperare template memorizzati in un database, in una cache (come Redis o Memcached), in un sistema di controllo di versione (come Git, in base a uno specifico commit) o generati dinamicamente.
- Implementazione di convenzioni di denominazione personalizzate:** potreste voler usare alias più brevi per i template o implementare una logica di ricerca specifica (ad esempio, cercare prima nella directory del tema e poi ritornare a una directory predefinita).
- Aggiunta di sicurezza o controllo degli accessi:** Un caricatore personalizzato potrebbe verificare i permessi dell'utente prima di caricare alcuni template.
- Preelaborazione:** Anche se in genere è sconsigliato( è meglioun passaggio del compilatore ), un caricatore potrebbe teoricamente preelaborare il contenuto dei template prima di passarlo a Latte.
Si configura il caricatore per la propria istanza di Latte\Engine
utilizzando il metodo
setLoader()
:
$latte = new Latte\Engine;
// Utilizzare il FileLoader predefinito per i file in '/path/to/templates'.
$loader = new Latte\Loaders\FileLoader('/path/to/templates');
$latte->setLoader($loader);
Un caricatore deve implementare l'interfaccia Latte\Loader
.
Caricatori incorporati
Latte fornisce diversi caricatori standard:
FileLoader
È il caricatore predefinito usato da Latte\Engine
se non viene specificato nessun altro caricatore. Carica
i modelli direttamente dal filesystem.
È possibile impostare facoltativamente una directory principale per limitare l'accesso:
use Latte\Loaders\FileLoader;
// La seguente soluzione consente di caricare i template solo all'interno di /var/www/html/templates
$loader = new FileLoader('/var/www/html/templates');
$latte->setLoader($loader);
// $latte->render('../../../etc/passwd'); // Questo lancerebbe un'eccezione
// Renderizza il template situato in /var/www/html/templates/pages/contact.latte
$latte->render('pages/contact.latte');
Risolve i nomi dei template relativamente al template corrente quando si usano tag come {include}
o
{layout}
, a meno che non venga fornito un percorso assoluto.
Caricatore di stringhe
Questo caricatore recupera il contenuto dei template da un array associativo, dove le chiavi sono i nomi dei template (identificatori) e i valori sono le stringhe del codice sorgente del template. È particolarmente utile per i test o per piccole applicazioni in cui i template possono essere memorizzati all'interno del codice PHP stesso.
use Latte\Loaders\StringLoader;
$loader = new StringLoader([
'main.latte' => 'Hello {$name}, include is below:{include helper.latte}',
'helper.latte' => '{var $x = 10}Included content: {$x}',
// Aggiungere altri modelli se necessario
]);
$latte->setLoader($loader);
$latte->render('main.latte', ['name' => 'World']);
// Output: Hello World, include è sotto:Contenuto incluso: 10
Se si ha bisogno di rendere un singolo template direttamente da una stringa, senza bisogno di inclusioni o ereditarietà che
facciano riferimento ad altri template con nome di stringa, si può passare la stringa direttamente a render()
o a
renderToString()
quando si usa StringLoader
senza un array:
$loader = new StringLoader;
$latte->setLoader($loader);
$templateString = 'Hello {$name}!';
$output = $latte->renderToString($templateString, ['name' => 'Alice']);
// $output contiene 'Ciao Alice!
Creazione di un caricatore personalizzato
Per creare un caricatore personalizzato (ad esempio, per caricare i modelli da un database, dalla cache, dal controllo di versione o da un'altra fonte), occorre creare una classe che implementi l'interfaccia Latte\Loader.
Vediamo cosa deve fare ogni metodo.
getContent (string $name): string
È il metodo principale del caricatore. Ha il compito di recuperare e restituire il contenuto completo del codice sorgente del
modello identificato da $name
(come passato a $latte->render()
o restituito da getReferredName()).
Se non è possibile trovare o accedere al template, questo metodo deve lanciare un
Latte\RuntimeException
.
public function getContent(string $name): string
{
// Esempio: Recupero da un ipotetico archivio interno
$content = $this->storage->read($name);
if ($content === null) {
throw new Latte\RuntimeException("Template '$name' cannot be loaded.");
}
return $content;
}
getReferredName (string $name, string $referringName): string
Questo metodo gestisce la risoluzione dei nomi dei template usati all'interno di tag come {include}
,
{layout}
, ecc. Quando Latte incontra, ad esempio, {include 'partial.latte'}
all'interno di
main.latte
, richiama questo metodo con $name = 'partial.latte'
e
$referringName = 'main.latte'
.
Il metodo ha il compito di risolvere $name
in un identificatore canonico (ad esempio, un percorso assoluto, una
chiave di database univoca), che verrà utilizzato per chiamare altri metodi del caricatore, in base al contesto fornito da
$referringName
.
public function getReferredName(string $name, string $referringName): string
{
return ...;
}
getUniqueId (string $name): string
Latte utilizza la cache dei modelli compilati per migliorare le prestazioni. Ogni file di modello compilato ha bisogno di un
nome unico derivato dall'identificatore del modello sorgente. Questo metodo fornisce una stringa che identifica in modo
univoco il modello $name
.
Per i modelli basati su file, può andare bene il percorso assoluto. Per i modelli di database, è comune una combinazione di un prefisso e dell'ID del database.
public function getUniqueId(string $name): string
{
return ...;
}
Esempio: Semplice caricatore di database
Questo esempio mostra la struttura di base di un caricatore che recupera i modelli memorizzati in una tabella del database
denominata templates
con le colonne name
(identificatore univoco), content
e
updated_at
.
use Latte;
class DatabaseLoader implements Latte\Loader
{
public function __construct(
private \PDO $db,
) {
}
public function getContent(string $name): string
{
$stmt = $this->db->prepare('SELECT content FROM templates WHERE name = ?');
$stmt->execute([$name]);
$content = $stmt->fetchColumn();
if ($content === false) {
throw new Latte\RuntimeException("Template '$name' not found in database.");
}
return $content;
}
// Questo semplice esempio presuppone che i nomi dei template ("homepage", "articolo", ecc.)
// siano ID unici e che i template non facciano riferimento l'uno all'altro in modo relativo.
public function getReferredName(string $name, string $referringName): string
{
return $name;
}
public function getUniqueId(string $name): string
{
// L'uso di un prefisso e del nome stesso è unico e sufficiente.
return 'db_' . $name;
}
}
// Uso:
$pdo = new \PDO(/* connection details */);
$loader = new DatabaseLoader($pdo);
$latte->setLoader($loader);
$latte->render('homepage'); // Carica il template con il nome 'homepage' dal DB
I caricatori personalizzati permettono di controllare completamente la provenienza dei modelli Latte, consentendo l'integrazione con diversi sistemi di archiviazione e flussi di lavoro.