Modelli
Nette utilizza il sistema di template Latte. Latte è utilizzato perché è il sistema di template più sicuro per PHP e allo stesso tempo il più intuitivo. Non è necessario imparare molto di nuovo, basta conoscere PHP e alcuni tag di Latte.
Di solito la pagina viene completata dal modello di layout + il modello di azione. Ecco come potrebbe apparire un modello di
layout, notando i blocchi {block}
e il tag {include}
:
<!DOCTYPE html>
<html>
<head>
<title>{block title}My App{/block}</title>
</head>
<body>
<header>...</header>
{include content}
<footer>...</footer>
</body>
</html>
E questo potrebbe essere il modello di azione:
{block title}Homepage{/block}
{block content}
<h1>Homepage</h1>
...
{/block}
Definisce il blocco content
, che viene inserito al posto di {include content}
nel layout, e
ridefinisce anche il blocco title
, che sovrascrive {block title}
nel layout. Provate a immaginare il
risultato.
Ricerca di modelli
Nei presentatori, non è necessario specificare quale template debba essere reso; il framework determinerà automaticamente il percorso, semplificando la codifica.
Se si utilizza una struttura di cartelle in cui ogni presentatore ha una propria cartella, è sufficiente posizionare il
template in questa cartella sotto il nome dell'azione (cioè della vista). Ad esempio, per l'azione default
,
utilizzare il modello default.latte
:
app/ └── UI/ └── Home/ ├── HomePresenter.php └── default.latte
Se si utilizza una struttura in cui i presentatori sono riuniti in una directory e i modelli in una cartella
templates
, salvare il tutto in un file <Presenter>.<view>.latte
oppure
<Presenter>/<view>.latte
:
app/ └── Presenters/ ├── HomePresenter.php └── templates/ ├── Home.default.latte ← 1st variant └── Home/ └── default.latte ← 2nd variant
La directory templates
può anche essere collocata un livello più in alto, allo stesso livello della directory
con le classi dei presentatori.
Se il modello non viene trovato, il presentatore risponde con un errore 404 – pagina non trovata.
È possibile modificare la vista utilizzando $this->setView('anotherView')
. È anche possibile specificare
direttamente il file del modello con $this->template->setFile('/path/to/template.latte')
.
I file in cui vengono cercati i modelli possono essere modificati sovrascrivendo il metodo formatTemplateFiles(), che restituisce un array di possibili nomi di file.
Ricerca dei modelli di layout
Nette cerca automaticamente anche il file di layout.
Se si utilizza una struttura di directory in cui ogni presentatore ha una propria directory, collocare il layout nella cartella del presentatore, se è specifico solo per lui, oppure a un livello superiore se è comune a più presentatori:
app/ └── UI/ ├── @layout.latte ← common layout └── Home/ ├── @layout.latte ← only for Home presenter ├── HomePresenter.php └── default.latte
Se si utilizza una struttura in cui i presentatori sono raggruppati in una directory e i modelli si trovano in una cartella
templates
, il layout sarà previsto nei seguenti punti:
app/ └── Presenters/ ├── HomePresenter.php └── templates/ ├── @layout.latte ← common layout ├── Home.@layout.latte ← only for Home, 1st variant └── Home/ └── @layout.latte ← only for Home, 2nd variant
Se il presentatore si trova in un modulo, cercherà anche più in alto nell'albero della directory, in base alla nidificazione del modulo.
Il nome del layout può essere modificato con $this->setLayout('layoutAdmin')
e sarà previsto nel file
@layoutAdmin.latte
. È anche possibile specificare direttamente il file del modello di layout usando
$this->setLayout('/path/to/template.latte')
.
L'uso di $this->setLayout(false)
o del tag {layout none}
all'interno del template disabilita la
ricerca del layout.
I file in cui vengono cercati i modelli di layout possono essere modificati sovrascrivendo il metodo formatLayoutTemplateFiles(), che restituisce un array di possibili nomi di file.
Variabili nel modello
Le variabili vengono passate al template scrivendole in $this->template
e poi sono disponibili nel template
come variabili locali:
$this->template->article = $this->articles->getById($id);
In questo modo possiamo passare facilmente qualsiasi variabile ai template. Tuttavia, quando si sviluppano applicazioni robuste, spesso è più utile limitarsi. Per esempio, definendo esplicitamente un elenco di variabili che il template si aspetta e i loro tipi. Ciò consentirà a PHP di effettuare il controllo dei tipi, all'IDE di effettuare il completamento automatico in modo corretto e all'analisi statica di rilevare gli errori.
Come si definisce un'enumerazione di questo tipo? Semplicemente sotto forma di una classe e delle sue proprietà. La chiamiamo
in modo simile a presenter, ma con Template
alla fine:
/**
* @property-read ArticleTemplate $template
*/
class ArticlePresenter extends Nette\Application\UI\Presenter
{
}
class ArticleTemplate extends Nette\Bridges\ApplicationLatte\Template
{
public Model\Article $article;
public Nette\Security\User $user;
// e altre variabili
}
L'oggetto $this->template
nel presentatore sarà ora un'istanza della classe ArticleTemplate
.
Quindi PHP controllerà i tipi dichiarati quando vengono scritti. A partire da PHP 8.2, inoltre, avvertirà di scrivere su una
variabile inesistente; nelle versioni precedenti si può ottenere lo stesso risultato utilizzando il tratto Nette\SmartObject.
L'annotazione @property-read
è per l'IDE e l'analisi statica, farà funzionare il completamento automatico,
vedere PhpStorm e il completamento del codice
per $this->template.
Ci si può concedere il lusso di sussurrare anche nei template, basta installare il plugin Latte in PhpStorm e specificare il nome della classe all'inizio del template, si veda l'articolo Latte: come digitare il sistema:
{templateType App\UI\Article\ArticleTemplate}
...
Questo è anche il modo in cui i template funzionano nei componenti, basta seguire la convenzione di denominazione e creare
una classe template FifteenTemplate
per il componente, ad esempio FifteenControl
.
Se si vuole creare una classe $template
come istanza di un'altra classe, usare il metodo
createTemplate()
:
public function renderDefault(): void
{
$template = $this->createTemplate(SpecialTemplate::class);
$template->foo = 123;
// ...
$this->sendTemplate($template);
}
Variabili predefinite
I presentatori e i componenti passano automaticamente diverse variabili utili ai modelli:
$basePath
è un percorso URL assoluto alla cartella principale (ad esempio/CD-collection
)$baseUrl
è un URL assoluto alla cartella principale (per esempiohttp://localhost/CD-collection
)$user
è un oggetto che rappresenta l'utente$presenter
è il presentatore corrente$control
è il componente o presentatore corrente$flashes
è un elenco di messaggi inviati dal metodoflashMessage()
Se si utilizza una classe modello personalizzata, queste variabili vengono passate se si crea una proprietà per esse.
Creazione di collegamenti
Nel modello si creano collegamenti ad altri presentatori e azioni come segue:
<a n:href="Product:show">detail</a>
L'attributo n:href
è molto utile per i tag HTML <a>
. Se vogliamo stampare il link altrove, ad
esempio nel testo, usiamo {link}
:
URL is: {link Home:default}
Per ulteriori informazioni, vedere Creazione di collegamenti.
Filtri personalizzati, tag, ecc.
Il sistema di template Latte può essere esteso con filtri personalizzati, funzioni, tag, ecc. Questo può essere fatto
direttamente nel metodo render<View>
o nel metodo beforeRender()
:
public function beforeRender(): void
{
// aggiunta di un filtro
$this->template->addFilter('foo', /* ... */);
// oppure configurare direttamente l'oggetto LatteEngine
$latte = $this->template->getLatte();
$latte->addFilterLoader(/* ... */);
}
La versione 3 di Latte offre un metodo più avanzato, creando un'estensione per ogni progetto web. Ecco un esempio approssimativo di una classe di questo tipo:
namespace App\UI\Accessory;
final class LatteExtension extends Latte\Extension
{
public function __construct(
private App\Model\Facade $facade,
private Nette\Security\User $user,
// ...
) {
}
public function getFilters(): array
{
return [
'timeAgoInWords' => $this->filterTimeAgoInWords(...),
'money' => $this->filterMoney(...),
// ...
];
}
public function getFunctions(): array
{
return [
'canEditArticle' =>
fn($article) => $this->facade->canEditArticle($article, $this->user->getId()),
// ...
];
}
// ...
}
La registriamo usando configuration:
latte:
extensions:
- App\UI\Accessory\LatteExtension
Tradurre
Se si sta programmando un'applicazione multilingue, è probabile che sia necessario produrre parte del testo del modello in
lingue diverse. A tale scopo, il framework Nette definisce un'interfaccia di traduzione Nette\Localization\Translator, che ha un
unico metodo translate()
. Questo accetta il messaggio $message
, che di solito è una stringa, e
qualsiasi altro parametro. Il compito è quello di restituire la stringa tradotta. Non esiste un'implementazione predefinita in
Nette, ma si può scegliere in base alle proprie esigenze tra diverse soluzioni già pronte che si possono trovare su Componette. La loro documentazione spiega come configurare il
traduttore.
I modelli possono essere configurati con un traduttore, che ci verrà
passato, utilizzando il metodo setTranslator()
:
protected function beforeRender(): void
{
// ...
$this->template->setTranslator($translator);
}
In alternativa, il traduttore può essere impostato utilizzando la configurazione:
latte:
extensions:
- Latte\Essential\TranslatorExtension(@Nette\Localization\Translator)
Il traduttore può essere utilizzato, ad esempio, come filtro |translate
, con parametri aggiuntivi passati al
metodo translate()
(vedere foo, bar
):
<a href="basket">{='Basket'|translate}</a>
<span>{$item|translate}</span>
<span>{$item|translate, foo, bar}</span>
Oppure come tag underscore:
<a href="basket">{_'Basket'}</a>
<span>{_$item}</span>
<span>{_$item, foo, bar}</span>
Per la traduzione di sezioni di template, esiste un tag accoppiato {translate}
(da Latte 2.11, in precedenza si
usava il tag {_}
):
<a href="order">{translate}Order{/translate}</a>
<a href="order">{translate foo, bar}Order{/translate}</a>
Il traduttore viene chiamato per impostazione predefinita in fase di esecuzione durante il rendering del template. La versione 3 di Latte, tuttavia, può tradurre tutto il testo statico durante la compilazione del modello. Ciò consente di risparmiare sulle prestazioni, perché ogni stringa viene tradotta una sola volta e la traduzione risultante viene scritta nel modello 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:
protected function beforeRender(): void
{
// ...
$this->template->setTranslator($translator, $lang);
}
Per testo statico si intende, ad esempio, {_'hello'}
o {translate}hello{/translate}
. Il testo non
statico, come {_$foo}
, continuerà a essere compilato al volo.