Nette Documentation Preview

syntax
Kommentare
**********

Der Blog wurde eingerichtet, wir haben einige sehr gute Blogbeiträge geschrieben und sie über Adminer veröffentlicht. Die Leute lesen den Blog und sind sehr begeistert von unseren Ideen. Wir erhalten jeden Tag viele E-Mails mit Lob. Aber was nützt all das Lob, wenn wir es nur in der E-Mail bekommen, so dass niemand sonst es lesen kann? Wäre es nicht besser, wenn die Leute direkt im Blog kommentieren könnten, damit alle anderen lesen können, wie toll wir sind?

Lasst uns alle Artikel kommentierbar machen.


Eine neue Tabelle erstellen .[#toc-creating-a-new-table]
========================================================

Starten Sie Adminer erneut und erstellen Sie eine neue Tabelle mit dem Namen `comments` mit diesen Spalten:

- `id` int, Prüfung auf Autoinkrement (AI)
- `post_id`, ein Fremdschlüssel, der auf die Tabelle `posts` verweist
- `name` varchar, Länge 255
- `email` varchar, Länge 255
- `content` text
- `created_at` Zeitstempel

Es sollte wie folgt aussehen:

[* adminer-comments.webp *]

Vergessen Sie nicht, die InnoDB-Tabellenspeicherung zu verwenden und klicken Sie auf Speichern.

```sql
CREATE TABLE `comments` (
	`id` int NOT NULL AUTO_INCREMENT PRIMARY KEY,
	`post_id` int(11) NOT NULL,
	`name` varchar(250) NOT NULL,
	`email` varchar(250) NOT NULL,
	`content` text NOT NULL,
	`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
	FOREIGN KEY (`post_id`) REFERENCES `posts` (`id`)
) ENGINE=InnoDB CHARSET=utf8;
```


Formular für Kommentare .[#toc-form-for-commenting]
===================================================

Zuerst müssen wir ein Formular erstellen, das es den Benutzern ermöglicht, auf unserer Seite zu kommentieren. Nette Framework hat eine großartige Unterstützung für Formulare. Sie können in einem Presenter konfiguriert und in einer Vorlage gerendert werden.

Nette Framework hat ein Konzept von *Komponenten*. Eine **Komponente** ist eine wiederverwendbare Klasse oder ein Stück Code, das mit einer anderen Komponente verbunden werden kann. Auch ein Präsentator ist eine Komponente. Jede Komponente wird mit Hilfe der Komponentenfabrik erstellt. Definieren wir also die Kommentarformularfabrik in `PostPresenter`.

```php .{file:app/Presenters/PostPresenter.php}
protected function createComponentCommentForm(): Form
{
	$form = new Form; // bedeutet Nette\Application\UI\Form

	$form->addText('name', 'Ihr Name:')
		->setRequired();

	$form->addEmail('email', 'Email:');

	$form->addTextArea('content', 'Kommentar:')
		->setRequired();

	$form->addSubmit('send', 'Kommentar veröffentlichen');

	return $form;
}
```

Erklären wir sie ein wenig. Die erste Zeile erzeugt eine neue Instanz der Komponente `Form`. Die folgenden Methoden fügen HTML-Eingaben in die Formulardefinition ein. `->addText` wird als `<input type=text name=name>`mit `<label>Your name:</label>`. Wie Sie vielleicht schon erraten haben, fügt die `->addTextArea` ein `<textarea>` und `->addSubmit` fügt ein `<input type=submit>`. Es gibt noch weitere Methoden dieser Art, aber das ist alles, was Sie im Moment wissen müssen. Sie können [mehr in der Dokumentation erfahren |forms:].

Sobald die Formularkomponente in einem Presenter definiert ist, können wir sie in einer Vorlage rendern (anzeigen). Dazu platzieren Sie das Tag `{control}` am Ende der Post-Detail-Vorlage in `Post/show.latte`. Da der Name der Komponente `commentForm` ist (er leitet sich vom Namen der Methode `createComponentCommentForm` ab), sieht das Tag wie folgt aus

```latte .{file:app/Presenters/templates/Post/show.latte}
...
<h2>Post new comment</h2>

{control commentForm}
```

Wenn Sie sich nun die Details eines Beitrags ansehen, wird ein neues Formular für die Eingabe von Kommentaren angezeigt.


Speichern in der Datenbank .[#toc-saving-to-database]
=====================================================

Haben Sie versucht, einige Daten zu übermitteln? Vielleicht haben Sie bemerkt, dass das Formular keine Aktion ausführt. Es ist einfach da, sieht cool aus und tut nichts. Wir müssen eine Callback-Methode anhängen, die die übermittelten Daten speichert.

Fügen Sie die folgende Zeile vor der Zeile `return` in der Komponentenfabrik für `commentForm` ein:

```php
$form->onSuccess[] = $this->commentFormSucceeded(...);
```

Sie bedeutet "nachdem das Formular erfolgreich abgeschickt wurde, rufe die Methode `commentFormSucceeded` des aktuellen Präsentators auf". Diese Methode existiert noch nicht, also erstellen wir sie.

```php .{file:app/Presenters/PostPresenter.php}
private function commentFormSucceeded(\stdClass $data): void
{
	$postId = $this->getParameter('postId');

	$this->database->table('comments')->insert([
		'post_id' => $postId,
		'name' => $data->name,
		'email' => $data->email,
		'content' => $data->content,
	]);

	$this->flashMessage('Thank you for your comment', 'success');
	$this->redirect('this');
}
```

Sie sollten sie direkt nach der Komponentenfabrik `commentForm` platzieren.

Die neue Methode hat ein Argument, nämlich die Instanz des übermittelten Formulars, die von der Komponentenfabrik erstellt wurde. Wir erhalten die übermittelten Werte in `$data`. Und dann fügen wir die Daten in die Datenbanktabelle `comments` ein.

Es gibt noch zwei weitere Methodenaufrufe zu erklären. Der Redirect leitet buchstäblich zur aktuellen Seite um. Das sollten Sie jedes Mal tun, wenn das Formular übermittelt wurde, gültig ist und die Callback-Operation das getan hat, was sie hätte tun sollen. Wenn Sie die Seite nach dem Absenden des Formulars umleiten, wird auch nicht die bekannte Meldung `Would you like to submit the post data again?` angezeigt, die Sie manchmal im Browser sehen können. (Im Allgemeinen sollten Sie den Benutzer nach dem Absenden eines Formulars mit der Methode `POST` immer zu einer Aktion `GET` weiterleiten).

Die `flashMessage` dient dazu, den Benutzer über das Ergebnis einer bestimmten Operation zu informieren. Da wir eine Routing vornehmen, kann die Nachricht nicht direkt an die Vorlage übergeben und gerendert werden. Deshalb gibt es diese Methode, die sie speichert und beim nächsten Laden der Seite zur Verfügung stellt. Die Flash-Nachrichten werden in der Standarddatei `app/Presenters/templates/@layout.latte` gerendert und sehen wie folgt aus:

```latte
<div n:foreach="$flashes as $flash" n:class="flash, $flash->type">
	{$flash->message}
</div>
```

Wie wir bereits wissen, werden sie automatisch an die Vorlage übergeben, so dass Sie nicht viel darüber nachdenken müssen, es funktioniert einfach. Für weitere Details [siehe die Dokumentation |application:presenters#flash-messages].


Rendering der Kommentare .[#toc-rendering-the-comments]
=======================================================

Dies ist eines der Dinge, die Sie einfach lieben werden. Nette Database hat diese coole Funktion namens [Explorer |database:explorer]. Erinnern Sie sich, dass wir die Tabellen als InnoDB erstellt haben? Adminer hat die sogenannten [Fremdschlüssel |https://dev.mysql.com/doc/refman/8.0/en/create-table-foreign-keys.html] erstellt, die uns eine Menge Arbeit ersparen werden.

Der Nette Database Explorer verwendet die Fremdschlüssel, um die Beziehungen zwischen den Tabellen aufzulösen, und da er die Beziehungen kennt, kann er automatisch Abfragen für Sie erstellen.

Wie Sie sich vielleicht erinnern, haben wir die Variable `$post` an die Vorlage in `PostPresenter::renderShow()` übergeben, und jetzt wollen wir alle Kommentare durchgehen, deren Spalte `post_id` gleich unserer `$post->id` ist. Sie können dies tun, indem Sie `$post->related('comments')` aufrufen. So einfach ist das. Sehen Sie sich den resultierenden Code an.

```php .{file:app/Presenters/PostPresenter.php}
public function renderShow(int $postId): void
{
	...
	$this->template->post = $post;
	$this->template->comments = $post->related('comments')->order('created_at');
}
```

Und die Vorlage:

```latte .{file:app/Presenters/templates/Post/show.latte}
...
<h2>Comments</h2>

<div class="comments">
	{foreach $comments as $comment}
		<p><b><a href="mailto:{$comment->email}" n:tag-if="$comment->email">
			{$comment->name}
		</a></b> said:</p>

		<div>{$comment->content}</div>
	{/foreach}
</div>
...
```

Beachten Sie das spezielle Attribut `n:tag-if`. Sie wissen bereits, wie `n: attributes` funktioniert. Wenn Sie dem Attribut `tag-` vorangestellt haben, umschließt es nur die Tags, nicht deren Inhalt. So können Sie den Namen des Kommentators in einen Link umwandeln, wenn er seine E-Mail-Adresse angegeben hat. Diese beiden Zeilen sind im Ergebnis identisch:

```latte
<strong n:tag-if="$important"> Hello there! </strong>

{if $important}<strong>{/if} Hello there! {if $important}</strong>{/if}
```

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

Kommentare

Der Blog wurde eingerichtet, wir haben einige sehr gute Blogbeiträge geschrieben und sie über Adminer veröffentlicht. Die Leute lesen den Blog und sind sehr begeistert von unseren Ideen. Wir erhalten jeden Tag viele E-Mails mit Lob. Aber was nützt all das Lob, wenn wir es nur in der E-Mail bekommen, so dass niemand sonst es lesen kann? Wäre es nicht besser, wenn die Leute direkt im Blog kommentieren könnten, damit alle anderen lesen können, wie toll wir sind?

Lasst uns alle Artikel kommentierbar machen.

Eine neue Tabelle erstellen

Starten Sie Adminer erneut und erstellen Sie eine neue Tabelle mit dem Namen comments mit diesen Spalten:

  • id int, Prüfung auf Autoinkrement (AI)
  • post_id, ein Fremdschlüssel, der auf die Tabelle posts verweist
  • name varchar, Länge 255
  • email varchar, Länge 255
  • content text
  • created_at Zeitstempel

Es sollte wie folgt aussehen:

Vergessen Sie nicht, die InnoDB-Tabellenspeicherung zu verwenden und klicken Sie auf Speichern.

CREATE TABLE `comments` (
	`id` int NOT NULL AUTO_INCREMENT PRIMARY KEY,
	`post_id` int(11) NOT NULL,
	`name` varchar(250) NOT NULL,
	`email` varchar(250) NOT NULL,
	`content` text NOT NULL,
	`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
	FOREIGN KEY (`post_id`) REFERENCES `posts` (`id`)
) ENGINE=InnoDB CHARSET=utf8;

Formular für Kommentare

Zuerst müssen wir ein Formular erstellen, das es den Benutzern ermöglicht, auf unserer Seite zu kommentieren. Nette Framework hat eine großartige Unterstützung für Formulare. Sie können in einem Presenter konfiguriert und in einer Vorlage gerendert werden.

Nette Framework hat ein Konzept von Komponenten. Eine Komponente ist eine wiederverwendbare Klasse oder ein Stück Code, das mit einer anderen Komponente verbunden werden kann. Auch ein Präsentator ist eine Komponente. Jede Komponente wird mit Hilfe der Komponentenfabrik erstellt. Definieren wir also die Kommentarformularfabrik in PostPresenter.

protected function createComponentCommentForm(): Form
{
	$form = new Form; // bedeutet Nette\Application\UI\Form

	$form->addText('name', 'Ihr Name:')
		->setRequired();

	$form->addEmail('email', 'Email:');

	$form->addTextArea('content', 'Kommentar:')
		->setRequired();

	$form->addSubmit('send', 'Kommentar veröffentlichen');

	return $form;
}

Erklären wir sie ein wenig. Die erste Zeile erzeugt eine neue Instanz der Komponente Form. Die folgenden Methoden fügen HTML-Eingaben in die Formulardefinition ein. ->addText wird als <input type=text name=name>mit <label>Your name:</label>. Wie Sie vielleicht schon erraten haben, fügt die ->addTextArea ein <textarea> und ->addSubmit fügt ein <input type=submit>. Es gibt noch weitere Methoden dieser Art, aber das ist alles, was Sie im Moment wissen müssen. Sie können mehr in der Dokumentation erfahren.

Sobald die Formularkomponente in einem Presenter definiert ist, können wir sie in einer Vorlage rendern (anzeigen). Dazu platzieren Sie das Tag {control} am Ende der Post-Detail-Vorlage in Post/show.latte. Da der Name der Komponente commentForm ist (er leitet sich vom Namen der Methode createComponentCommentForm ab), sieht das Tag wie folgt aus

...
<h2>Post new comment</h2>

{control commentForm}

Wenn Sie sich nun die Details eines Beitrags ansehen, wird ein neues Formular für die Eingabe von Kommentaren angezeigt.

Speichern in der Datenbank

Haben Sie versucht, einige Daten zu übermitteln? Vielleicht haben Sie bemerkt, dass das Formular keine Aktion ausführt. Es ist einfach da, sieht cool aus und tut nichts. Wir müssen eine Callback-Methode anhängen, die die übermittelten Daten speichert.

Fügen Sie die folgende Zeile vor der Zeile return in der Komponentenfabrik für commentForm ein:

$form->onSuccess[] = $this->commentFormSucceeded(...);

Sie bedeutet „nachdem das Formular erfolgreich abgeschickt wurde, rufe die Methode commentFormSucceeded des aktuellen Präsentators auf“. Diese Methode existiert noch nicht, also erstellen wir sie.

private function commentFormSucceeded(\stdClass $data): void
{
	$postId = $this->getParameter('postId');

	$this->database->table('comments')->insert([
		'post_id' => $postId,
		'name' => $data->name,
		'email' => $data->email,
		'content' => $data->content,
	]);

	$this->flashMessage('Thank you for your comment', 'success');
	$this->redirect('this');
}

Sie sollten sie direkt nach der Komponentenfabrik commentForm platzieren.

Die neue Methode hat ein Argument, nämlich die Instanz des übermittelten Formulars, die von der Komponentenfabrik erstellt wurde. Wir erhalten die übermittelten Werte in $data. Und dann fügen wir die Daten in die Datenbanktabelle comments ein.

Es gibt noch zwei weitere Methodenaufrufe zu erklären. Der Redirect leitet buchstäblich zur aktuellen Seite um. Das sollten Sie jedes Mal tun, wenn das Formular übermittelt wurde, gültig ist und die Callback-Operation das getan hat, was sie hätte tun sollen. Wenn Sie die Seite nach dem Absenden des Formulars umleiten, wird auch nicht die bekannte Meldung Would you like to submit the post data again? angezeigt, die Sie manchmal im Browser sehen können. (Im Allgemeinen sollten Sie den Benutzer nach dem Absenden eines Formulars mit der Methode POST immer zu einer Aktion GET weiterleiten).

Die flashMessage dient dazu, den Benutzer über das Ergebnis einer bestimmten Operation zu informieren. Da wir eine Routing vornehmen, kann die Nachricht nicht direkt an die Vorlage übergeben und gerendert werden. Deshalb gibt es diese Methode, die sie speichert und beim nächsten Laden der Seite zur Verfügung stellt. Die Flash-Nachrichten werden in der Standarddatei app/Presenters/templates/@layout.latte gerendert und sehen wie folgt aus:

<div n:foreach="$flashes as $flash" n:class="flash, $flash->type">
	{$flash->message}
</div>

Wie wir bereits wissen, werden sie automatisch an die Vorlage übergeben, so dass Sie nicht viel darüber nachdenken müssen, es funktioniert einfach. Für weitere Details siehe die Dokumentation.

Rendering der Kommentare

Dies ist eines der Dinge, die Sie einfach lieben werden. Nette Database hat diese coole Funktion namens Explorer. Erinnern Sie sich, dass wir die Tabellen als InnoDB erstellt haben? Adminer hat die sogenannten Fremdschlüssel erstellt, die uns eine Menge Arbeit ersparen werden.

Der Nette Database Explorer verwendet die Fremdschlüssel, um die Beziehungen zwischen den Tabellen aufzulösen, und da er die Beziehungen kennt, kann er automatisch Abfragen für Sie erstellen.

Wie Sie sich vielleicht erinnern, haben wir die Variable $post an die Vorlage in PostPresenter::renderShow() übergeben, und jetzt wollen wir alle Kommentare durchgehen, deren Spalte post_id gleich unserer $post->id ist. Sie können dies tun, indem Sie $post->related('comments') aufrufen. So einfach ist das. Sehen Sie sich den resultierenden Code an.

public function renderShow(int $postId): void
{
	...
	$this->template->post = $post;
	$this->template->comments = $post->related('comments')->order('created_at');
}

Und die Vorlage:

...
<h2>Comments</h2>

<div class="comments">
	{foreach $comments as $comment}
		<p><b><a href="mailto:{$comment->email}" n:tag-if="$comment->email">
			{$comment->name}
		</a></b> said:</p>

		<div>{$comment->content}</div>
	{/foreach}
</div>
...

Beachten Sie das spezielle Attribut n:tag-if. Sie wissen bereits, wie n: attributes funktioniert. Wenn Sie dem Attribut tag- vorangestellt haben, umschließt es nur die Tags, nicht deren Inhalt. So können Sie den Namen des Kommentators in einen Link umwandeln, wenn er seine E-Mail-Adresse angegeben hat. Diese beiden Zeilen sind im Ergebnis identisch:

<strong n:tag-if="$important"> Hello there! </strong>

{if $important}<strong>{/if} Hello there! {if $important}</strong>{/if}