Seite mit einem Beitrag

Nun erstellen wir eine weitere Seite des Blogs, die einen bestimmten Beitrag anzeigt.

Wir müssen eine neue Render-Methode erstellen, die einen bestimmten Artikel abruft und an das Template übergibt. Diese Methode in HomePresenter zu haben, ist nicht sehr schön, da wir über einen Artikel sprechen und nicht über die Startseite. Erstellen wir also PostPresenter in app/Presentation/Post/. Dieser Presenter muss sich ebenfalls mit der Datenbank verbinden, daher schreiben wir hier wieder einen Konstruktor, der eine Datenbankverbindung erfordert.

PostPresenter könnte also 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 korrekten Namespace App\Presentation\Post anzugeben, der der Einstellung des Presenter-Mappings unterliegt.

Die Methode renderShow benötigt ein Argument – die ID eines bestimmten Artikels, der angezeigt werden soll. Dann lädt sie diesen Artikel aus der Datenbank und übergibt ihn an das Template.

In das Template Home/default.latte fügen wir einen Link zur Aktion Post:show ein.

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

Das Tag {link} generiert eine URL-Adresse, die auf die Aktion Post:show verweist. Es übergibt auch die ID des Beitrags als Argument.

Dasselbe können wir kürzer mit einem n:Attribut schreiben:

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

Das Attribut n:href ist analog zum Tag {link}.

Für die Aktion Post:show existiert jedoch noch kein Template. Wir können versuchen, den Link zu diesem Beitrag zu öffnen. Tracy zeigt einen Fehler an, da das Template Post/show.latte noch nicht existiert. Wenn Sie eine andere Fehlermeldung sehen, müssen Sie wahrscheinlich mod_rewrite auf dem Webserver aktivieren.

Erstellen wir also das Template 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>

Gehen wir nun die einzelnen Teile des Templates durch.

Die erste Zeile beginnt mit der Definition eines Blocks namens “content”, genauso wie auf der Startseite. Dieser Block wird wieder im Haupt-Template angezeigt. Wie Sie sehen, fehlt das schließende Tag {/block}. Das ist nämlich optional.

Auf der nächsten Zeile befindet sich ein Link zurück zur Blog-Beitragsliste, sodass sich der Benutzer einfach zwischen der Beitragsliste und einem einzelnen Beitrag bewegen kann. Da wir das Attribut n:href verwenden, kümmert sich Nette selbst um die Generierung von Links. Der Link verweist auf die Aktion default des Presenters Home (wir können auch n:href="Home:" schreiben, da die Aktion mit dem Namen default weggelassen werden kann, sie wird automatisch ergänzt).

Die dritte Zeile formatiert die Datumsausgabe mit einem Filter, den wir bereits kennen.

Die vierte Zeile zeigt den Titel des Blogs im HTML-Tag <h1> an. Dieses Tag enthält ein Attribut, das Sie vielleicht nicht kennen (n:block="title"). Raten Sie mal, was es tut? Wenn Sie den vorherigen Teil aufmerksam gelesen haben, wissen Sie bereits, dass es sich um ein n:Attribut handelt. Dies ist ein weiteres Beispiel dafür, das äquivalent ist zu:

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

Einfach gesagt, dieser Block definiert den Block namens title neu. Dieser Block ist bereits im Haupt-Layout-Template (/app/Presentation/@layout.latte:11) definiert, und wie bei der Überlagerung von Methoden in OOP wird dieser Block im Haupt-Template vollständig überlagert. Somit enthält der <title> der Seite nun den Titel des angezeigten Beitrags, und dafür mussten wir nur ein einfaches Attribut n:block="title" verwenden. Großartig, nicht wahr?

Die fünfte und letzte Zeile des Templates zeigt den gesamten Inhalt eines bestimmten Beitrags an.

Überprüfung der Beitrags-ID

Was passiert, wenn jemand die ID in der URL ändert und eine nicht existierende id einfügt? Wir sollten dem Benutzer einen netten Fehler vom Typ “Seite nicht gefunden” anbieten. Ändern wir also die Render-Methode im PostPresenter ein wenig:

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

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

Wenn der Beitrag nicht gefunden werden kann, zeigen wir durch den Aufruf von $this->error(...) eine Fehlerseite 404 mit einer verständlichen Meldung an. Beachten Sie, dass Sie diese Fehlerseite im Entwicklermodus (localhost) nicht sehen werden. Stattdessen wird Tracy mit Details zur Ausnahme angezeigt, was für die Entwicklung ziemlich vorteilhaft ist. Wenn wir uns beide Modi anzeigen lassen möchten, ändern wir einfach das Argument der Methode setDebugMode in der Datei Bootstrap.php.

Zusammenfassung

Wir haben eine Datenbank mit Beiträgen und eine Webanwendung, die zwei Ansichten hat – die erste zeigt eine Übersicht aller Beiträge und die zweite zeigt einen bestimmten Beitrag an.