Nette Documentation Preview

syntax
Blog-Startseite
***************

.[perex]
Erstellen wir die Startseite, auf der Ihre letzten Beiträge angezeigt werden.


Bevor wir beginnen, sollten Sie zumindest einige Grundlagen über das Model-View-Presenter-Designmuster (ähnlich wie MVC((Model-View-Controller))) kennen:

- **Modell** - Datenverarbeitungsschicht. Sie ist vollständig vom Rest der Anwendung getrennt. Sie kommuniziert nur mit den Präsentatoren.

- **View** - eine Front-End-Definitionsschicht. Sie stellt dem Benutzer die angeforderten Daten mithilfe von Vorlagen dar.

- **Presenter** (oder Controller) - eine Verbindungsschicht. Der Presenter verbindet Model und View. Bearbeitet Anfragen, fragt das Modell nach Daten und übergibt sie dann an die aktuelle Ansicht.


Im Falle einer sehr einfachen Anwendung wie unserem Blog besteht die Model-Schicht eigentlich nur aus Abfragen an die Datenbank selbst - wir brauchen keinen zusätzlichen PHP-Code dafür. Wir müssen nur Presenter- und View-Schichten erstellen. In Nette hat jeder Presenter seine eigenen Views, also werden wir mit beiden gleichzeitig fortfahren.


Erstellen der Datenbank mit Adminer .[#toc-creating-the-database-with-adminer]
==============================================================================

Um die Daten zu speichern, werden wir die MySQL-Datenbank verwenden, da sie unter Webentwicklern die häufigste Wahl ist. Wenn Ihnen das nicht zusagt, können Sie natürlich eine Datenbank Ihrer Wahl verwenden.

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

Um die Datenbank zu erstellen, können wir [Adminer |https://www.adminer.org] herunterladen, oder Sie können ein anderes Tool für die Datenbankverwaltung verwenden.


Öffnen wir Adminer und erstellen wir eine neue Datenbank mit dem Namen `quickstart`.

Erstellen Sie eine neue Tabelle mit dem Namen `posts` und fügen Sie diese Spalten hinzu:
- `id` int, klicken Sie auf autoincrement (AI)
- `title` varchar, Länge 255
- `content` text
- `created_at` Zeitstempel

Es sollte wie folgt aussehen:

[* adminer-posts.webp *]

```sql
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;
```

.[caution]
Es ist sehr wichtig, den **InnoDB**-Tabellenspeicher zu verwenden. Sie werden den Grund dafür später sehen. Wählen Sie das jetzt einfach aus und senden Sie es ab. Sie können jetzt auf Speichern klicken.

Versuchen Sie, einige Beispiel-Blogbeiträge hinzuzufügen, bevor wir die Möglichkeit implementieren, neue Beiträge direkt aus unserer Anwendung heraus hinzuzufügen.

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


Verbinden mit der Datenbank .[#toc-connecting-to-the-database]
==============================================================

Jetzt, wo die Datenbank erstellt ist und wir einige Beiträge darin haben, ist es an der Zeit, sie auf unserer neuen glänzenden Seite anzuzeigen.

Zuerst müssen wir unserer Anwendung mitteilen, welche Datenbank sie verwenden soll. Die Konfiguration der Datenbankverbindung wird in `config/common.neon` gespeichert. Legen Sie die Verbindung DSN((Data Source Name)) und Ihre Anmeldedaten fest. Es sollte so aussehen:

```neon .{file:config/common.neon}
database:
	dsn: 'mysql:host=127.0.0.1;dbname=quickstart'
	user: *enter user name*
	password: *enter password here*
```

.[note]
Achten Sie bei der Bearbeitung dieser Datei auf die Einrückung. Das [NEON-Format |neon:format] akzeptiert sowohl Leerzeichen als auch Tabulatoren, aber nicht beides zusammen! Die Konfigurationsdatei im Webprojekt verwendet standardmäßig Tabulatoren.


Injizieren der Datenbankverbindung .[#toc-injecting-the-database-connection]
============================================================================

Der Presenter `HomePresenter`, der die Artikel auflistet, benötigt eine Datenbankverbindung. Um sie zu erhalten, schreiben Sie einen Konstruktor wie diesen:

```php .{file:app/UI/Home/HomePresenter.php}
<?php
namespace App\UI\Home;

use Nette;

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

	// ...
}
```


Laden von Beiträgen aus der Datenbank .[#toc-loading-posts-from-the-database]
=============================================================================

Holen wir nun die Beiträge aus der Datenbank und übergeben sie an die Vorlage, die dann den HTML-Code rendert. Dafür ist die sogenannte *render*-Methode gedacht:

```php .{file:app/UI/Home/HomePresenter.php}
public function renderDefault(): void
{
	$this->template->posts = $this->database
		->table('posts')
		->order('created_at DESC')
		->limit(5);
}
```

Der Presenter hat jetzt eine Render-Methode `renderDefault()`, die Daten an eine Ansicht namens `default` weitergibt. Presenter-Vorlagen befinden sich in `app/UI/{PresenterName}/{viewName}.latte`, in diesem Fall also in `app/UI/Home/default.latte`. In der Vorlage ist nun eine Variable namens `$posts` verfügbar, die die Beiträge aus der Datenbank enthält.


Vorlage .[#toc-template]
========================

Es gibt eine allgemeine Vorlage für die gesamte Seite (genannt *Layout*, mit Kopfzeile, Stylesheets, Fußzeile, ...) und dann spezifische Vorlagen für jede Ansicht (z.B. für die Anzeige der Liste der Blogbeiträge), die einige Teile der Layout-Vorlage überschreiben können.

Standardmäßig befindet sich die Layout-Vorlage im Verzeichnis `app/UI/@layout.latte`, das Folgendes enthält:

```latte .{file:app/UI/@layout.latte}
...
{include content}
...
```

`{include content}` fügt einen Block namens `content` in die Hauptvorlage ein. Sie können ihn in den Vorlagen der einzelnen Ansichten definieren. In diesem Fall werden wir die Datei `Home/default.latte` wie folgt bearbeiten:

```latte .{file:app/UI/Home/default.latte}
{block content}
	Hello World
{/block}
```

Sie definiert den [Block |latte:tags#block]*Inhalt*, der in das Layout eingefügt wird. Wenn Sie den Browser aktualisieren, sehen Sie eine Seite mit dem Text "Hello world" (im Quellcode auch mit HTML-Kopf- und Fußzeile, die in `@layout.latte` definiert sind).

Zeigen wir nun die Blogeinträge an - wir werden die Vorlage wie folgt bearbeiten:

```latte .{file:app/UI/Home/default.latte}
{block content}
	<h1>My blog</h1>

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

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

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

Wenn Sie Ihren Browser aktualisieren, sehen Sie die Liste Ihrer Blogeinträge. Die Liste ist nicht sehr schick oder bunt, also fügen Sie ruhig etwas [glänzendes CSS |https://github.com/nette-examples/quickstart/blob/v4.0/www/css/style.css] zu `www/css/style.css` hinzu und verknüpfen Sie es mit einem Layout:

```latte .{file:app/UI/@layout.latte}
	...
	<link rel="stylesheet" href="{$basePath}/css/style.css">
</head>
...
```

Der Tag `{foreach}` durchläuft alle Beiträge, die der Vorlage in der Variablen `$posts` übergeben wurden, und zeigt für jeden Beitrag ein Stück HTML-Code an. Genau wie es ein PHP-Code tun würde.

Die Variable `|date` wird als Filter bezeichnet. Filter werden verwendet, um die Ausgabe zu formatieren. Dieser spezielle Filter wandelt ein Datum (z. B. `2013-04-12`) in seine besser lesbare Form um (`12. 4. 2013`). Der Filter `|truncate` schneidet die Zeichenkette auf die angegebene Maximallänge ab und fügt am Ende ein Auslassungszeichen ein, wenn die Zeichenkette abgeschnitten wird. Da es sich um eine Vorschau handelt, hat es keinen Sinn, den vollständigen Inhalt des Artikels anzuzeigen. Weitere Standardfilter finden [Sie in der Dokumentation |latte:filters] oder Sie können bei Bedarf eigene Filter erstellen.

Eine weitere Sache. Wir können den Code ein wenig kürzer und damit einfacher machen. Wir können *Latte Tags* durch *n:Attribute* wie folgt ersetzen:

```latte .{file:app/UI/Home/default.latte}
{block content}
	<h1>My 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}</div>
	</div>
{/block}
```

Der `n:foreach`, umhüllt einfach das *div* mit einem *foreach*-Block (er tut genau das Gleiche wie der vorherige Codeblock).


Zusammenfassung .[#toc-summary]
===============================

Wir haben eine sehr einfache MySQL-Datenbank mit einigen Blog-Beiträgen darin. Die Anwendung verbindet sich mit der Datenbank und zeigt eine einfache Liste der Beiträge an.

{{priority: -1}}
{{sitename: Nette Quickstart}}

Blog-Startseite

Erstellen wir die Startseite, auf der Ihre letzten Beiträge angezeigt werden.

Bevor wir beginnen, sollten Sie zumindest einige Grundlagen über das Model-View-Presenter-Designmuster (ähnlich wie MVC) kennen:

  • Modell – Datenverarbeitungsschicht. Sie ist vollständig vom Rest der Anwendung getrennt. Sie kommuniziert nur mit den Präsentatoren.
  • View – eine Front-End-Definitionsschicht. Sie stellt dem Benutzer die angeforderten Daten mithilfe von Vorlagen dar.
  • Presenter (oder Controller) – eine Verbindungsschicht. Der Presenter verbindet Model und View. Bearbeitet Anfragen, fragt das Modell nach Daten und übergibt sie dann an die aktuelle Ansicht.

Im Falle einer sehr einfachen Anwendung wie unserem Blog besteht die Model-Schicht eigentlich nur aus Abfragen an die Datenbank selbst – wir brauchen keinen zusätzlichen PHP-Code dafür. Wir müssen nur Presenter- und View-Schichten erstellen. In Nette hat jeder Presenter seine eigenen Views, also werden wir mit beiden gleichzeitig fortfahren.

Erstellen der Datenbank mit Adminer

Um die Daten zu speichern, werden wir die MySQL-Datenbank verwenden, da sie unter Webentwicklern die häufigste Wahl ist. Wenn Ihnen das nicht zusagt, können Sie natürlich eine Datenbank Ihrer Wahl verwenden.

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

Um die Datenbank zu erstellen, können wir Adminer herunterladen, oder Sie können ein anderes Tool für die Datenbankverwaltung verwenden.

Öffnen wir Adminer und erstellen wir eine neue Datenbank mit dem Namen quickstart.

Erstellen Sie eine neue Tabelle mit dem Namen posts und fügen Sie diese Spalten hinzu:

  • id int, klicken Sie auf autoincrement (AI)
  • title varchar, Länge 255
  • content text
  • created_at Zeitstempel

Es sollte wie folgt 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, den InnoDB-Tabellenspeicher zu verwenden. Sie werden den Grund dafür später sehen. Wählen Sie das jetzt einfach aus und senden Sie es ab. Sie können jetzt auf Speichern klicken.

Versuchen Sie, einige Beispiel-Blogbeiträge hinzuzufügen, bevor wir die Möglichkeit implementieren, neue Beiträge direkt aus unserer Anwendung heraus hinzuzufügen.

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

Verbinden mit der Datenbank

Jetzt, wo die Datenbank erstellt ist und wir einige Beiträge darin haben, ist es an der Zeit, sie auf unserer neuen glänzenden Seite anzuzeigen.

Zuerst müssen wir unserer Anwendung mitteilen, welche Datenbank sie verwenden soll. Die Konfiguration der Datenbankverbindung wird in config/common.neon gespeichert. Legen Sie die Verbindung DSN und Ihre Anmeldedaten fest. Es sollte so aussehen:

database:
	dsn: 'mysql:host=127.0.0.1;dbname=quickstart'
	user: *enter user name*
	password: *enter password here*

Achten Sie bei der Bearbeitung dieser Datei auf die Einrückung. Das NEON-Format akzeptiert sowohl Leerzeichen als auch Tabulatoren, aber nicht beides zusammen! Die Konfigurationsdatei im Webprojekt verwendet standardmäßig Tabulatoren.

Injizieren der Datenbankverbindung

Der Presenter HomePresenter, der die Artikel auflistet, benötigt eine Datenbankverbindung. Um sie zu erhalten, schreiben Sie einen Konstruktor wie diesen:

<?php
namespace App\UI\Home;

use Nette;

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

	// ...
}

Laden von Beiträgen aus der Datenbank

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

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

Der Presenter hat jetzt eine Render-Methode renderDefault(), die Daten an eine Ansicht namens default weitergibt. Presenter-Vorlagen befinden sich in app/UI/{PresenterName}/{viewName}.latte, in diesem Fall also in app/UI/Home/default.latte. In der Vorlage ist nun eine Variable namens $posts verfügbar, die die Beiträge aus der Datenbank enthält.

Vorlage

Es gibt eine allgemeine Vorlage für die gesamte Seite (genannt Layout, mit Kopfzeile, Stylesheets, Fußzeile, …) und dann spezifische Vorlagen für jede Ansicht (z.B. für die Anzeige der Liste der Blogbeiträge), die einige Teile der Layout-Vorlage überschreiben können.

Standardmäßig befindet sich die Layout-Vorlage im Verzeichnis app/UI/@layout.latte, das Folgendes enthält:

...
{include content}
...

{include content} fügt einen Block namens content in die Hauptvorlage ein. Sie können ihn in den Vorlagen der einzelnen Ansichten definieren. In diesem Fall werden wir die Datei Home/default.latte wie folgt bearbeiten:

{block content}
	Hello World
{/block}

Sie definiert den BlockInhalt, der in das Layout eingefügt wird. Wenn Sie den Browser aktualisieren, sehen Sie eine Seite mit dem Text „Hello world“ (im Quellcode auch mit HTML-Kopf- und Fußzeile, die in @layout.latte definiert sind).

Zeigen wir nun die Blogeinträge an – wir werden die Vorlage wie folgt bearbeiten:

{block content}
	<h1>My blog</h1>

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

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

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

Wenn Sie Ihren Browser aktualisieren, sehen Sie die Liste Ihrer Blogeinträge. Die Liste ist nicht sehr schick oder bunt, also fügen Sie ruhig etwas glänzendes CSS zu www/css/style.css hinzu und verknüpfen Sie es mit einem Layout:

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

Der Tag {foreach} durchläuft alle Beiträge, die der Vorlage in der Variablen $posts übergeben wurden, und zeigt für jeden Beitrag ein Stück HTML-Code an. Genau wie es ein PHP-Code tun würde.

Die Variable |date wird als Filter bezeichnet. Filter werden verwendet, um die Ausgabe zu formatieren. Dieser spezielle Filter wandelt ein Datum (z. B. 2013-04-12) in seine besser lesbare Form um (12. 4. 2013). Der Filter |truncate schneidet die Zeichenkette auf die angegebene Maximallänge ab und fügt am Ende ein Auslassungszeichen ein, wenn die Zeichenkette abgeschnitten wird. Da es sich um eine Vorschau handelt, hat es keinen Sinn, den vollständigen Inhalt des Artikels anzuzeigen. Weitere Standardfilter finden Sie in der Dokumentation oder Sie können bei Bedarf eigene Filter erstellen.

Eine weitere Sache. Wir können den Code ein wenig kürzer und damit einfacher machen. Wir können Latte Tags durch n:Attribute wie folgt ersetzen:

{block content}
	<h1>My 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}</div>
	</div>
{/block}

Der n:foreach, umhüllt einfach das div mit einem foreach-Block (er tut genau das Gleiche wie der vorherige Codeblock).

Zusammenfassung

Wir haben eine sehr einfache MySQL-Datenbank mit einigen Blog-Beiträgen darin. Die Anwendung verbindet sich mit der Datenbank und zeigt eine einfache Liste der Beiträge an.