Seite mit einem Beitrag
Ergänzen wir in unserem Blog eine weitere Seite, die den Inhalt eines bestimmten Beitrags anzeigt.
Wir müssen eine neue Render-Methode erstellen, die einen bestimmten Beitrag holt und an das Template übergibt. Diese Methode
in den HomePresenter zu legen, ist nicht besonders sauber, denn es geht um einen einzelnen Beitrag, nicht um die
Startseite. Erstellen wir also eine neue Klasse PostPresenter und legen sie in app/Presentation/Post/
ab. Auch dieser Presenter braucht eine Datenbankverbindung, wir ergänzen also den Konstruktor, der die Datenbankverbindung
verlangt.
Der PostPresenter könnte so aussehen:
<?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);
}
}
Wir dürfen nicht vergessen, den richtigen Namespace App\Presentation\Post anzugeben, der von der Konfiguration
des Presenter-Mappings abhängt.
Die Methode renderShow verlangt ein Argument – die ID des anzuzeigenden Beitrags. Sie lädt den Beitrag dann
aus der Datenbank und übergibt ihn an das Template.
Im Template Home/default.latte ergänzen wir einen Link auf die Aktion Post:show:
...
<h2><a href="{link Post:show $post->id}">{$post->title}</a></h2>
...
Der Tag {link} erzeugt eine URL-Adresse, die auf die Aktion Post:show zeigt. Er übergibt außerdem
die ID des Beitrags als Argument.
Dasselbe lässt sich mit einem n:Attribut knapper schreiben:
...
<h2><a n:href="Post:show $post->id">{$post->title}</a></h2>
...
Das Attribut n:href entspricht dem Tag {link}.
Das Template für die Aktion Post:show existiert allerdings noch nicht. Wir können versuchen, den Link zu diesem
Beitrag zu öffnen. Tracy zeigt einen Fehler an, weil das Template
Post/show.latte noch nicht existiert. Sehen Sie eine andere Fehlermeldung, müssen Sie vermutlich
mod_rewrite auf Ihrem Webserver aktivieren.
Wir erstellen also Post/show.latte mit diesem Inhalt:
{block content}
<p><a n:href="Home:default">← zurück zur Beitragsliste</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>
Sehen wir uns nun die einzelnen Teile des Templates an.
Die erste Zeile beginnt die Definition eines Blocks namens “content”, genau wie auf der Startseite. Dieser Block wird
wieder innerhalb des Haupt-Layout-Templates angezeigt. Wie Sie sehen, fehlt der schließende Tag {/block}. Er ist
optional.
Die zweite Zeile bietet einen Rücklink zur Liste der Blogbeiträge, damit der Benutzer bequem zwischen der Beitragsliste und
einem bestimmten Beitrag wechseln kann. Wir verwenden wieder das Attribut n:href, sodass sich Nette um das Erzeugen
der URL kümmert. Der Link zeigt auf die Aktion default des Presenters Home (Sie könnten auch
n:href="Home:" schreiben, denn der Aktionsname default kann entfallen; er wird automatisch
ergänzt).
Die dritte Zeile formatiert das Datum mit einem Filter, den wir bereits kennen.
Die vierte Zeile zeigt den Titel des Blogbeitrags innerhalb eines HTML-Tags <h1> an. Dieser Tag
enthält ein Attribut, das Sie vielleicht nicht kennen (n:block="title"). Können Sie erraten, was es tut? Wenn Sie
den vorigen Abschnitt aufmerksam gelesen haben, wissen Sie bereits, dass es ein n:Attribut ist. Das ist ein weiteres
Beispiel, gleichbedeutend mit:
{block title}<h1>{$post->title}</h1>{/block}
Einfach gesagt definiert dieser Block den Block namens title neu. Dieser Block ist bereits im
Haupt-Layout-Template definiert (/app/Presentation/@layout.latte:11), und genau wie beim Überschreiben von
Methoden in der OOP überschreibt dieser Block den im Haupt-Template. Der <title> der Seite enthält nun also
den Titel des angezeigten Beitrags, und dafür genügte dieses einfache Attribut n:block="title".
Großartig, oder?
Die fünfte und letzte Zeile des Templates zeigt den vollständigen Inhalt des jeweiligen Beitrags an.
Überprüfung der Beitrags-ID
Was passiert, wenn jemand die ID in der URL verändert und eine nicht existierende id einsetzt? Wir sollten dem
Benutzer eine schöne Fehlerseite “Seite nicht gefunden” zeigen. Ändern wir die Render-Methode im PostPresenter
leicht ab:
public function renderShow(int $id): void
{
$post = $this->database
->table('posts')
->get($id);
if (!$post) {
$this->error('Beitrag nicht gefunden');
}
$this->template->post = $post;
}
Lässt sich der Beitrag nicht finden, zeigt der Aufruf von $this->error(...) eine 404-Seite mit einer
verständlichen Meldung. Beachten Sie, dass Sie diese Fehlerseite in der Entwicklungsumgebung (auf localhost) nicht sehen.
Stattdessen zeigt Tracy die Exception mit allen Details, was für die Entwicklung recht praktisch ist. Wenn Sie beide Modi testen
wollen, ändern Sie einfach das Argument, das der Methode setDebugMode in Bootstrap.php
übergeben wird.
Zusammenfassung
Wir haben eine Datenbank mit Beiträgen und eine Webanwendung mit zwei Views – der erste zeigt eine Übersicht aller Beiträge, der zweite einen bestimmten Beitrag.