Pagina di un singolo articolo
Aggiungiamo al nostro blog un'altra pagina, che mostrerà il contenuto di un singolo articolo.
Dobbiamo creare un nuovo metodo render che ottenga un articolo specifico e lo passi al template. Mettere questo metodo in
HomePresenter non è molto pulito, perché si tratta di un singolo articolo e non della pagina principale. Creiamo
quindi una nuova classe PostPresenter e mettiamola in app/Presentation/Post/. Anche questo presenter
avrà bisogno della connessione al database, quindi aggiungeremo il costruttore che la richiede.
Il PostPresenter può apparire così:
<?php
namespace App\Presentation\Post;
use Nette;
use Nette\Application\UI\Form;
final class PostPresenter extends Nette\Application\UI\Presenter
{
public function __construct(
private Nette\Database\Explorer $database,
) {
}
public function renderShow(int $id): void
{
$this->template->post = $this->database
->table('posts')
->get($id);
}
}
Non dobbiamo dimenticare di indicare il namespace corretto App\Presentation\Post, che dipende dalla configurazione
della mappatura dei presenter.
Il metodo renderShow richiede un argomento, l'ID dell'articolo da mostrare. Carica poi l'articolo dal database e
lo passa al template.
Nel template Home/default.latte aggiungiamo un link all'azione Post:show:
...
<h2><a href="{link Post:show $post->id}">{$post->title}</a></h2>
...
Il tag {link} genera un indirizzo URL che punta all'azione Post:show. Passa inoltre come argomento
l'ID dell'articolo.
La stessa cosa si può scrivere in modo conciso con un n:attributo:
...
<h2><a n:href="Post:show $post->id">{$post->title}</a></h2>
...
L'attributo n:href è analogo al tag {link}.
Il template per l'azione Post:show però non esiste ancora. Possiamo provare ad aprire il link a questo articolo.
Tracy mostrerà un errore, perché il template Post/show.latte non esiste
ancora. Se vedete un messaggio di errore diverso, probabilmente dovete attivare mod_rewrite sul vostro
server web.
Creiamo quindi Post/show.latte con questo contenuto:
{block content}
<p><a n:href="Home:default">← torna all'elenco degli articoli</a></p>
<div class="date">{$post->created_at|date:'j. n. Y'}</div>
<h1 n:block="title">{$post->title}</h1>
<div class="post">{$post->content}</div>
Passiamo ora in rassegna le singole parti del template.
La prima riga apre la definizione di un blocco chiamato “content”, proprio come nella pagina principale. Questo blocco
verrà di nuovo mostrato dentro il template di layout principale. Come vedete, manca il tag di chiusura {/block}. È
facoltativo.
La seconda riga offre un link di ritorno all'elenco degli articoli del blog, così l'utente può muoversi facilmente tra
l'elenco e un singolo articolo. Usiamo di nuovo l'attributo n:href, quindi Nette si occuperà di generare l'URL. Il
link punta all'azione default del presenter Home (potreste anche scrivere n:href="Home:",
perché il nome dell'azione default si può omettere, viene aggiunto automaticamente).
La terza riga formatta la data con un filtro che già conosciamo.
La quarta riga mostra il titolo dell'articolo dentro un tag HTML <h1>. Questo tag contiene un
attributo che forse non conoscete (n:block="title"). Indovinate che cosa fa? Se avete letto attentamente la sezione
precedente, sapete già che è un n:attributo. È un altro esempio, equivalente a:
{block title}<h1>{$post->title}</h1>{/block}
In parole semplici, questo blocco ridefinisce il blocco chiamato title. Questo blocco è già definito nel
template layout principale (/app/Presentation/@layout.latte:11) e, proprio come la ridefinizione dei metodi
nell'OOP, questo blocco sovrascrive quello del template principale. Il <title> della pagina conterrà quindi
ora il titolo dell'articolo mostrato, e ci è bastato questo semplice attributo n:block="title".
Fantastico, vero?
La quinta e ultima riga del template mostra il contenuto completo del singolo articolo.
Verifica dell'ID dell'articolo
Che cosa succede se qualcuno modifica l'ID nell'URL e inserisce un id inesistente? Dovremmo mostrare all'utente un
bel messaggio di errore “pagina non trovata”. Modifichiamo leggermente il metodo render in PostPresenter:
public function renderShow(int $id): void
{
$post = $this->database
->table('posts')
->get($id);
if (!$post) {
$this->error('Articolo non trovato');
}
$this->template->post = $post;
}
Se l'articolo non si trova, la chiamata $this->error(...) mostrerà una pagina 404 con un messaggio
comprensibile. Notate che nell'ambiente di sviluppo (su localhost) questa pagina di errore non la vedrete. Al suo posto Tracy
mostrerà l'eccezione con tutti i dettagli, il che è molto comodo per lo sviluppo. Se volete provare entrambe le modalità,
basta cambiare l'argomento passato al metodo setDebugMode in Bootstrap.php.
Riepilogo
Abbiamo un database con gli articoli e un'applicazione web con due viste: la prima mostra una panoramica di tutti gli articoli, la seconda mostra un singolo articolo.