Stránka s příspěvkem

Nyní si vytvoříme další stránku blogu, která bude zobrazovat jeden konkrétní příspěvek.

Musíme si vytvořit novou render metodu, která získá jeden konkrétní článek a předá jej do šablony. Mít tuto metodu v HomePresenter není moc hezké, protože se bavíme o článku a ne úvodní stránce. Vytvořme si tedy PostPresenter v app/Presenters. Tento presenter se také potřebuje připojit k databázi, takže zde opět napíšeme konstruktor, který bude vyžadovat databázové připojení.

PostPresenter by mohl tedy vypadat takto:

<?php
namespace App\Presenters;

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 $postId): void
	{
		$this->template->post = $this->database
			->table('posts')
			->get($postId);
	}
}

Nesmíme zapomenout uvést správný namespace App\Presenters, který podléhá nastavení mapování presenterů.

Metoda renderShow vyžaduje jeden argument – ID jednoho konkrétního článku, který má být zobrazen. Poté tento článek načte z databáze a předá ho do šablony.

Do šablony Home/default.latte vložíme odkaz na akci Post:show.

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

Značka {link} generuje URL adresu, která směřuje na akci Post:show. Také předává ID příspěvku jako argument.

Totéž můžeme zapsat zkráceně pomocí n:atributu:

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

Atribut n:href je obdobou tagu {link}.

Pro akci Post:show však ještě neexistuje šablona. Můžeme si vyzkoušet otevřít odkaz na tento příspěvek. Tracy zobrazí error, protože šablona Post/show.latte ještě neexistuje. Pokud vidíte jiné chybové hlášení, tak pravděpodobně budete muset zapnout mod_rewrite na webserveru.

Vytvoříme tedy šablonu Post/show.latte s tímto obsahem:

{block content}

<p><a n:href="Home:default">← zpět na výpis příspěvků</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>

Nyní si projdeme jednotlivé části šablony.

První řádka začíná definici bloku s názvem „content“ stejně jako tomu bylo na úvodní stránce. Tento blok bude opět zobrazen v hlavní šabloně. Jak vidíte, chybí koncová značka {/block}. Ta je totiž nepovinná.

Na další řádce je odkaz zpět na výpis článků blogu, takže se uživatel může jednoduše pohybovat mezi výpisem článků a jedním konkrétním. Protože používáme atribut n:href, tak se Nette samo postará o generování odkazů. Odkaz směřuje na akci default presenteru Home (můžeme napsat také n:href="Home:", protože akce s názvem default může být vynechána, doplní se automaticky).

Třetí řádka formátuje výpis data pomocí filtru, který už známe.

Čtvrtá řádka zobrazuje titulek blogu v HTML tagu <h1>. Tento tag obsahuje atribut, který možná neznáte (n:block="title"). Uhodnete, co dělá? Pokud jste četli předchozí část pozorně, tak již víte, že se jedná o n:atribut. Toto je jejich další příklad, který je ekvivalentní k:

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

Jednoduše řečeno, tento blok předefinovává blok s názvem title. Tento blok je již definován v hlavní layout šabloně (/app/Presenters/templates/@layout.latte:11) a tak jako u překrývání metod v OOP, úplně stejně se tento blok v hlavní šabloně překryje. Takže <title> stránky nyní obsahuje titulek zobrazeného příspěvku a stačilo nám k tomu použít pouze jednoho jednoduchého atributu n:block="title". Skvělé, že?

Pátá a poslední řádka šablony zobrazuje celý obsah jednoho konkrétního příspěvku.

Kontrola ID příspěvku

Co se stane, když někdo změní ID v URL a vloží nějaké neexistující postId? Měli bychom uživateli nabídnout pěknou chybu typu „stránka nebyla nalezena“. Pozměníme tedy trošku render metodu v PostPresenter:

public function renderShow(int $postId): void
{
	$post = $this->database
		->table('posts')
		->get($postId);
	if (!$post) {
		$this->error('Stránka nebyla nalezena');
	}

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

Pokud nemůže být příspěvek nalezen, zavoláním $this->error(...) zobrazíme chybovou stránku 404 se srozumitelnou hláškou. Pozor na to, že ve vývojářském módu (localhost) tuto chybovou stránku neuvidíte. Místo toho se ukáže Tracy s detaily o výjimce, což je docela výhodné pro vývoj. Chceme-li si nechat zobrazit oba módy, stačí pouze změnit argument metody setDebugMode v souboru Bootstrap.php.

Shrnutí

Máme databázi s příspěvky a webovou aplikaci, která má dva pohledy – první zobrazuje přehled všech příspěvků a druhá zobrazuje jeden konkrétní příspěvek.