Pagina con il post

Ora creeremo un'altra pagina del blog che visualizzerà un singolo post specifico.

Dobbiamo creare un nuovo metodo render che ottenga un articolo specifico e lo passi al template. Avere questo metodo in HomePresenter non è molto bello, perché stiamo parlando di un articolo e non della pagina iniziale. Creiamo quindi PostPresenter in app/Presentation/Post/. Questo presenter ha anche bisogno di connettersi al database, quindi scriveremo di nuovo un costruttore che richiederà la connessione al database.

PostPresenter potrebbe quindi 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 specificare il namespace corretto App\Presentation\Post, che è soggetto all'impostazione del mapping dei presenter.

Il metodo renderShow richiede un argomento – l'ID di un articolo specifico che deve essere visualizzato. Successivamente carica questo articolo dal database e lo passa al template.

Nel template Home/default.latte inseriamo 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 anche l'ID del post come argomento.

Lo stesso possiamo scriverlo in forma abbreviata usando un n:attributo:

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

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

Per l'azione Post:show, tuttavia, non esiste ancora un template. Possiamo provare ad aprire il link a questo post. Tracy visualizzerà un errore, perché il template Post/show.latte non esiste ancora. Se vedete un messaggio di errore diverso, probabilmente dovrete abilitare mod_rewrite sul webserver.

Creiamo quindi il template Post/show.latte con questo contenuto:

{block content}

<p><a n:href="Home:default">← torna all'elenco dei post</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>

Ora esaminiamo le singole parti del template.

La prima riga inizia la definizione del blocco con il nome “content” proprio come sulla pagina iniziale. Questo blocco sarà nuovamente visualizzato nel template principale. Come vedete, manca il tag di chiusura {/block}. Questo è infatti facoltativo.

Sulla riga successiva c'è un link per tornare all'elenco degli articoli del blog, così l'utente può muoversi facilmente tra l'elenco degli articoli e uno specifico. Poiché usiamo l'attributo n:href, Nette si occupa da solo della generazione dei link. Il link punta all'azione default del presenter Home (possiamo scrivere anche n:href="Home:", perché l'azione con il nome default può essere omessa, viene aggiunta automaticamente).

La terza riga formatta la visualizzazione della data usando il filtro che già conosciamo.

La quarta riga visualizza il titolo del blog nel tag HTML <h1>. Questo tag contiene un attributo che forse non conoscete (n:block="title"). Indovinate cosa fa? Se avete letto attentamente la parte precedente, sapete già che si tratta di un n:attributo. Questo è un altro esempio, che è equivalente a:

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

In parole povere, questo blocco ridefinisce il blocco con il nome title. Questo blocco è già definito nel template principale layout (/app/Presentation/@layout.latte:11) e, proprio come nella sovrascrittura dei metodi in OOP, questo blocco nel template principale viene sovrascritto allo stesso modo. Quindi il <title> della pagina ora contiene il titolo del post visualizzato e ci è bastato usare solo un semplice attributo n:block="title". Fantastico, vero?

La quinta e ultima riga del template visualizza l'intero contenuto di un post specifico.

Controllo dell'ID del post

Cosa succede se qualcuno cambia l'ID nell'URL e inserisce un id inesistente? Dovremmo offrire all'utente un bell'errore del tipo “pagina non trovata”. Modifichiamo quindi un po' il metodo render in PostPresenter:

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

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

Se il post non può essere trovato, chiamando $this->error(...) visualizziamo una pagina di errore 404 con un messaggio comprensibile. Attenzione al fatto che in modalità sviluppatore (localhost) non vedrete questa pagina di errore. Al suo posto apparirà Tracy con i dettagli sull'eccezione, il che è abbastanza vantaggioso per lo sviluppo. Se vogliamo visualizzare entrambe le modalità, basta semplicemente cambiare l'argomento del metodo setDebugMode nel file Bootstrap.php.

Abbiamo un database con i post e un'applicazione web che ha due viste – la prima visualizza un riepilogo di tutti i post e la seconda visualizza un post specifico.