Pagina del singolo post

Aggiungiamo un'altra pagina al nostro blog, che mostrerà il contenuto di un particolare post.

Dobbiamo creare un nuovo metodo di rendering, che recupererà un post specifico del blog e lo passerà al template. Avere questa vista in HomePresenter non è bello, perché si tratta di un post del blog, non della homepage. Quindi, creiamo una nuova classe PostPresenter e posizioniamola in app/UI/Post/. Avrà bisogno di una connessione al database, quindi inseriamo di nuovo il codice database injection.

PostPresenter dovrebbe avere questo aspetto:

<?php
namespace App\UI\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);
	}
}

Dobbiamo impostare un namespace App\UI\Post corretto per il nostro presentatore. Dipende dalla mappatura del presentatore.

Il metodo renderShow richiede un solo parametro: l'ID del post da visualizzare. Quindi, carica il post dal database e passa il risultato al template.

Nel modello 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. Questo tag inoltra anche l'ID del post come argomento.

Lo stesso si può scrivere brevemente usando n:attribute:

...
<h2><a n:href="Post:show $post->id">{$post->title}</a></h2>
...

L'attributo n:href è simile al tag {link}.

Il template per l'azione Post:show non esiste ancora. Possiamo aprire un link a questo post. Tracy mostrerà un errore, perché Post/show.latte non esiste. Se viene visualizzato un altro errore, probabilmente è necessario attivare il mod_rewrite nel server web.

Creeremo quindi Post/show.latte con questo contenuto:

{block content}

<p><a n:href="Home:default">← back to posts list</a></p>

<div class="date">{$post->created_at|date:'F j, Y'}</div>

<h1 n:block="title">{$post->title}</h1>

<div class="post">{$post->content}</div>

Diamo un'occhiata alle singole parti.

La prima riga inizia la definizione di un blocco con nome chiamato “content”, che abbiamo visto in precedenza. Verrà visualizzato in un modello di layout. Come si può notare, manca il tag finale {/block}. È opzionale.

La seconda riga fornisce un backlink all'elenco dei post del blog, in modo che l'utente possa navigare agevolmente avanti e indietro nel nostro blog. Utilizziamo di nuovo l'attributo n:href, quindi Nette si occuperà di generare l'URL per noi. Il link punta all'azione default del presentatore Home (si potrebbe anche scrivere n:href="Home:", perché l'azione default può essere omessa).

La terza riga formatta il timestamp di pubblicazione con un filtro, come già sappiamo.

La quarta riga mostra il titolo del post del blog come un <h1> titolo. C'è una parte che forse non conoscete: n:block="title". Riuscite a indovinare cosa fa? Se avete letto attentamente le parti precedenti, abbiamo menzionato n: attributes. Questo è un altro esempio. È equivalente a:

{block title}<h1>{$post->title}</h1>{/block}

In parole povere, ridefinisce un blocco chiamato title. Il blocco è definito nel modello di layout (/app/UI/@layout.latte:11) e, come per l'overriding OOP, viene sovrascritto qui. Pertanto, la pagina <title> conterrà il titolo del post visualizzato. Abbiamo sovrascritto il titolo della pagina e tutto ciò di cui avevamo bisogno era n:block="title". Ottimo, no?

La quinta e ultima riga del template mostra il contenuto completo del post.

Controllo dell'ID del post

Cosa succede se qualcuno altera l'URL e inserisce id che non esiste? Dovremmo fornire all'utente un simpatico errore di “pagina non trovata”. Aggiorniamo il metodo di rendering in PostPresenter:

public function renderShow(int $id): void
{
	$post = $this->database
		->table('posts')
		->get($id);
	if (!$post) {
		$this->error('Post not found');
	}

	$this->template->post = $post;
}

Se il post non può essere trovato, la chiamata a $this->error(...) mostrerà una pagina 404 con un messaggio chiaro e comprensibile. Si noti che nell'ambiente di sviluppo (sul portatile), non si vedrà la pagina di errore. Invece, Tracy mostrerà l'eccezione con tutti i dettagli, il che è piuttosto comodo per lo sviluppo. È possibile controllare entrambe le modalità, basta cambiare il valore passato a setDebugMode in Bootstrap.php.

Riepilogo

Abbiamo un database con i post di un blog e un'applicazione web con due viste: la prima visualizza il riepilogo di tutti i post recenti e la seconda visualizza un post specifico.