Pagina cu postarea

Acum vom crea o altă pagină a blogului, care va afișa o postare specifică.

Trebuie să creăm o nouă metodă render, care va obține un articol specific și îl va transmite șablonului. A avea această metodă în HomePresenter nu este foarte elegant, deoarece vorbim despre un articol și nu despre pagina de pornire. Să creăm deci PostPresenter în app/Presentation/Post/. Acest presenter trebuie, de asemenea, să se conecteze la baza de date, așa că vom scrie din nou aici un constructor care va necesita conexiunea la baza de date.

PostPresenter ar putea arăta deci astfel:

<?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);
	}
}

Nu trebuie să uităm să specificăm spațiul de nume corect App\Presentation\Post, care este supus setărilor de maparea presenterilor.

Metoda renderShow necesită un argument – ID-ul unui articol specific care trebuie afișat. Apoi încarcă acest articol din baza de date și îl transmite șablonului.

În șablonul Home/default.latte inserăm un link către acțiunea Post:show.

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

Tag-ul {link} generează adresa URL care indică spre acțiunea Post:show. De asemenea, transmite ID-ul postării ca argument.

Același lucru îl putem scrie prescurtat folosind n:atributul:

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

Atributul n:href este echivalentul tag-ului {link}.

Pentru acțiunea Post:show însă, nu există încă un șablon. Putem încerca să deschidem linkul către această postare. Tracy va afișa o eroare, deoarece șablonul Post/show.latte nu există încă. Dacă vedeți un alt mesaj de eroare, probabil va trebui să activați mod_rewrite pe serverul web.

Creăm deci șablonul Post/show.latte cu acest conținut:

{block content}

<p><a n:href="Home:default">← înapoi la lista postărilor</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>

Acum vom parcurge părțile individuale ale șablonului.

Prima linie începe definiția blocului cu numele “content”, la fel cum a fost pe pagina de pornire. Acest bloc va fi din nou afișat în șablonul principal. După cum vedeți, lipsește tag-ul de închidere {/block}. Acesta este, de fapt, opțional.

Pe linia următoare este un link înapoi la lista articolelor blogului, astfel încât utilizatorul să poată naviga ușor între lista articolelor și unul specific. Deoarece folosim atributul n:href, Nette se ocupă singur de generarea linkurilor. Linkul indică spre acțiunea default a presenterului Home (putem scrie și n:href="Home:", deoarece acțiunea cu numele default poate fi omisă, se completează automat).

A treia linie formatează afișarea datei folosind filtrul pe care îl cunoaștem deja.

A patra linie afișează titlul blogului în tag-ul HTML <h1>. Acest tag conține un atribut pe care poate nu îl cunoașteți (n:block="title"). Ghiciți ce face? Dacă ați citit partea anterioară cu atenție, știți deja că este vorba despre un n:atribut. Acesta este un alt exemplu al lor, care este echivalent cu:

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

Simplu spus, acest bloc redefinește blocul cu numele title. Acest bloc este deja definit în șablonul layout principal (/app/Presentation/@layout.latte:11) și, la fel ca la suprascrierea metodelor în OOP, la fel acest bloc din șablonul principal va fi suprascris. Deci <title> paginii conține acum titlul postării afișate și ne-a fost suficient să folosim doar un singur atribut simplu n:block="title". Minunat, nu-i așa?

A cincea și ultima linie a șablonului afișează întregul conținut al unei postări specifice.

Verificarea ID-ului postării

Ce se întâmplă dacă cineva modifică ID-ul în URL și introduce un id inexistent? Ar trebui să oferim utilizatorului o eroare frumoasă de tipul “pagina nu a fost găsită”. Modificăm deci puțin metoda render în PostPresenter:

public function renderShow(int $id): void
{
	$post = $this->database
		->table('posts')
		->get($id);
	if (!$post) {
		$this->error('Pagina nu a fost găsită');
	}

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

Dacă postarea nu poate fi găsită, apelând $this->error(...) afișăm pagina de eroare 404 cu un mesaj inteligibil. Atenție, în modul dezvoltator (localhost) nu veți vedea această pagină de eroare. În schimb, se va afișa Tracy cu detalii despre excepție, ceea ce este destul de avantajos pentru dezvoltare. Dacă dorim să ne afișăm ambele moduri, este suficient să schimbăm argumentul metodei setDebugMode în fișierul Bootstrap.php.

Rezumat

Avem o bază de date cu postări și o aplicație web care are două vizualizări – prima afișează o prezentare generală a tuturor postărilor și a doua afișează o postare specifică.