Startseite des Blogs

Erstellen wir die Startseite, die Ihre neuesten Beiträge anzeigt.

Bevor wir beginnen, sollten Sie zumindest die Grundlagen des Entwurfsmusters Model-View-Presenter kennen (ähnlich MVC):

  • Model – die Schicht, die mit den Daten arbeitet. Sie ist vom Rest der Anwendung vollständig getrennt. Sie kommuniziert nur mit dem Presenter.
  • View – die Frontend-Schicht. Sie rendert die angeforderten Daten mithilfe von Templates und zeigt sie dem Benutzer.
  • Presenter (oder Controller) – die verbindende Schicht. Der Presenter verbindet das Model und den View. Er verarbeitet Requests, fordert vom Model Daten an und übergibt sie dann an den View.

Bei einer einfachen Anwendung wie unserem Blog besteht die gesamte Modellschicht nur aus Datenbankabfragen – dafür brauchen wir noch keinen zusätzlichen PHP-Code. Für den Anfang erstellen wir also nur Presenter und Templates. In Nette hat jeder Presenter seine eigenen Templates, deshalb erstellen wir sie gleichzeitig.

Erstellung der Datenbank mit Adminer

Zum Speichern der Daten verwenden wir eine MySQL-Datenbank, weil das die häufigste Wahl unter Webentwicklern ist. Wenn Sie sie nicht verwenden wollen, wählen Sie ruhig eine Datenbank Ihrer Wahl.

Bereiten wir die Struktur der Datenbank vor, in der unsere Blogbeiträge gespeichert werden. Wir können ganz einfach beginnen – mit einer einzigen Tabelle für die Beiträge.

Zum Anlegen der Datenbank können wir Adminer herunterladen oder ein anderes Werkzeug zur Datenbankverwaltung verwenden, das Sie bevorzugen.

Öffnen wir Adminer und legen wir eine neue Datenbank namens quickstart an.

Legen Sie eine neue Tabelle namens posts an und ergänzen Sie diese Spalten:

  • id int, autoincrement (AI) ankreuzen
  • title varchar, Länge 255
  • content text
  • created_at timestamp

Das sollte so aussehen:

CREATE TABLE `posts` (
	`id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
	`title` varchar(255) NOT NULL,
	`content` text NOT NULL,
	`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB CHARSET=utf8;

Es ist sehr wichtig, die Storage Engine InnoDB zu verwenden. Den Grund sehen Sie später. Wählen Sie sie vorerst einfach aus und klicken Sie auf Speichern.

Versuchen Sie, ein paar Beispielbeiträge von Hand hinzuzufügen, bevor wir das Hinzufügen neuer Beiträge direkt aus unserer Anwendung umsetzen.

INSERT INTO `posts` (`id`, `title`, `content`, `created_at`) VALUES
(1,	'Article One',	'Lorem ipsum dolor one',	CURRENT_TIMESTAMP),
(2,	'Article Two',	'Lorem ipsum dolor two',	CURRENT_TIMESTAMP),
(3,	'Article Three',	'Lorem ipsum dolor three',	CURRENT_TIMESTAMP);

Verbindung zur Datenbank herstellen

Jetzt, da die Datenbank angelegt ist und wir ein paar Beiträge darin haben, ist es der richtige Zeitpunkt, sie auf unserer brandneuen Seite anzuzeigen.

Zuerst müssen wir unserer Anwendung mitteilen, welche Datenbank sie verwenden soll. Die Konfiguration der Datenbankverbindung wird in der Datei config/common.neon über DSN und die Zugangsdaten gesetzt. Das sollte ungefähr so aussehen:

database:
	dsn: 'mysql:host=127.0.0.1;dbname=quickstart'
	user: *hier Ihren Benutzernamen eintragen*
	password: *hier Ihr Datenbankpasswort eintragen*

Achten Sie beim Bearbeiten dieser Datei auf die Einrückung. Das Format NEON akzeptiert sowohl Leerzeichen als auch Tabs, aber nicht beides gemeinsam. Die Standardkonfigurationsdatei im Web Project verwendet Tabs.

Datenbankverbindung injizieren

Der Presenter HomePresenter, der die Beiträge auflisten wird, braucht eine Datenbankverbindung. Um sie zu bekommen, verwenden wir den Konstruktor so:

<?php
namespace App\Presentation\Home;

use Nette;

final class HomePresenter extends Nette\Application\UI\Presenter
{
	public function __construct(
		private Nette\Database\Explorer $database,
	) {
	}

	// ...
}

Beiträge aus der Datenbank laden

Holen wir nun die Beiträge aus der Datenbank und übergeben wir sie an das Template, das daraus den HTML-Code rendert. Dafür ist die sogenannte render-Methode da:

public function renderDefault(): void
{
	$this->template->posts = $this->database
		->table('posts')
		->order('created_at DESC')
		->limit(5);
}

Der Presenter hat nun eine Render-Methode renderDefault(), die die Daten aus der Datenbank an das Template (den View) übergibt. Templates liegen in app/Presentation/{PresenterName}/{viewName}.latte, in diesem Fall also in app/Presentation/Home/default.latte. Im Template steht nun eine Variable $posts zur Verfügung, die die aus der Datenbank geholten Beiträge enthält.

Template

Für die gesamte Website haben wir ein Haupt-Template (das sogenannte Layout, das Kopf, Styles, Fuß usw. enthält) und eigene Templates für jeden View (etwa für die Anzeige der Blogbeiträge), die Teile des Haupt-Templates überschreiben können.

Standardmäßig liegt das Layout-Template in app/Presentation/@layout.latte und enthält:

...
{include content}
...

Der Tag {include content} fügt einen Block namens content in das Haupt-Template ein. Diesen Block definieren wir in den Templates der einzelnen Views. In unserem Fall ändern wir die Datei Home/default.latte folgendermaßen:

{block content}
	Hello World
{/block}

Damit haben wir den Block content definiert, der in das Haupt-Layout eingefügt wird. Wenn Sie den Browser erneut aktualisieren, sehen Sie eine Seite mit dem Text “Hello World” (im Quelltext samt HTML-Kopf und -Fuß, die in @layout.latte definiert sind).

Zeigen wir die Blogbeiträge an – wir ändern das Template folgendermaßen:

{block content}
	<h1>Mein Blog</h1>

	{foreach $posts as $post}
	<div class="post">
		<div class="date">{$post->created_at|date:'F j, Y'}</div>

		<h2>{$post->title}</h2>

		<div>{$post->content|truncate:256}</div>
	</div>
	{/foreach}
{/block}

Wenn Sie den Browser aktualisieren, sehen Sie die Liste Ihrer Blogbeiträge. Die Liste ist noch nicht besonders schick oder farbenfroh, ergänzen Sie also ruhig ein paar schöne CSS-Styles in der Datei www/css/style.css und binden Sie sie im Layout ein:

	...
	<link rel="stylesheet" href="{$basePath}/css/style.css">
</head>
...

Der Tag {foreach} iteriert über alle Beiträge, die dem Template in der Variablen $posts übergeben wurden, und gibt für jeden Beitrag ein Stück HTML-Code aus. Er verhält sich genauso wie PHP-Code.

Die Schreibweise |date: nennt man Filter. Filter dienen dazu, die Ausgabe zu formatieren. Dieser Filter wandelt ein Datum (z. B. 2013-04-12) in eine besser lesbare Form um (April 12, 2013). Der Filter |truncate kürzt den String auf die angegebene Höchstlänge und ergänzt am Ende Auslassungspunkte (…), wenn der String gekürzt wurde. Da es sich um eine Vorschau handelt, hat es keinen Sinn, den vollständigen Inhalt des Beitrags anzuzeigen. Weitere Standardfilter finden Sie in der Dokumentation, oder Sie erstellen bei Bedarf eigene.

Noch eines. Wir können den bisherigen Code kürzer und einfacher machen. Das erreichen wir, indem wir die Latte-Tags durch n:Attribute ersetzen:

{block content}
	<h1>Mein Blog</h1>

	<div n:foreach="$posts as $post" class="post">
		<div class="date">{$post->created_at|date:'F j, Y'}</div>

		<h2>{$post->title}</h2>

		<div>{$post->content|truncate:256}</div>
	</div>
{/block}

Das Attribut n:foreach umschließt den div-Block mit einer foreach-Schleife (es funktioniert genauso wie der vorherige Code).

Zusammenfassung

Wir haben nun eine sehr einfache MySQL-Datenbank mit ein paar Beiträgen. Die Anwendung verbindet sich mit dieser Datenbank und gibt eine einfache Liste dieser Beiträge in einem Template aus.