Erstellen wir ein Kontakt-Formular

Schauen wir uns an, wie man in Nette ein Kontaktformular erstellt und es an eine E-Mail sendet. Also, los geht's!

Zuerst müssen wir ein neues Projekt erstellen. Wie auf der Seite " Erste Schritte" erklärt wird. Und dann können wir mit der Erstellung des Formulars beginnen.

Der einfachste Weg ist, das Formular direkt in Presenter zu erstellen. Wir können die vorgefertigten HomePresenter verwenden. Wir werden die Komponente contactForm hinzufügen, die das Formular darstellt. Dies geschieht, indem wir die createComponentContactForm() Factory-Methode in den Code schreiben, der die Komponente erzeugt:

use Nette\Application\UI\Form;
use Nette\Application\UI\Presenter;

class HomePresenter extends Presenter
{
	protected function createComponentContactForm(): Form
	{
		$form = new Form;
		$form->addText('name', 'Name:')
			->setRequired('Enter your name');
		$form->addEmail('email', 'E-mail:')
			->setRequired('Enter your e-mail');
		$form->addTextarea('message', 'Message:')
			->setRequired('Enter message');
		$form->addSubmit('send', 'Send');
		$form->onSuccess[] = [$this, 'contactFormSucceeded'];
		return $form;
	}

	public function contactFormSucceeded(Form $form, $data): void
	{
		// sending an email
	}
}

Wie Sie sehen können, haben wir zwei Methoden erstellt. Die erste Methode createComponentContactForm() erstellt ein neues Formular. Dieses hat Felder für Name, E-Mail und Nachricht, die wir mit den Methoden addText(), addEmail() und addTextArea() hinzufügen. Wir haben auch eine Schaltfläche zum Absenden des Formulars hinzugefügt. Was aber, wenn der Benutzer einige Felder nicht ausfüllt? In diesem Fall sollten wir ihn darauf hinweisen, dass es sich um ein Pflichtfeld handelt. Wir haben dies mit der Methode setRequired() getan. Schließlich haben wir auch ein Ereignis onSuccess hinzugefügt, das ausgelöst wird, wenn das Formular erfolgreich abgeschickt wurde. In unserem Fall ruft es die Methode contactFormSucceeded auf, die sich um die Verarbeitung des übermittelten Formulars kümmert. Das fügen wir dem Code gleich hinzu.

Die Komponente contantForm soll in der Vorlage templates/Home/default.latte gerendert werden:

{block content}
<h1>Contant Form</h1>
{control contactForm}

Um die E-Mail selbst zu versenden, erstellen wir eine neue Klasse namens ContactFacade und platzieren sie in der Datei app/Model/ContactFacade.php:

<?php
declare(strict_types=1);

namespace App\Model;

use Nette\Mail\Mailer;
use Nette\Mail\Message;

class ContactFacade
{
	public function __construct(
		private Mailer $mailer,
	) {
	}

	public function sendMessage(string $email, string $name, string $message): void
	{
		$mail = new Message;
		$mail->addTo('admin@example.com') // your email
			->setFrom($email, $name)
			->setSubject('Message from the contact form')
			->setBody($message);

		$this->mailer->send($mail);
	}
}

Die Methode sendMessage() wird die E-Mail erstellen und versenden. Sie verwendet dazu einen so genannten Mailer, den sie als Abhängigkeit über den Konstruktor übergibt. Lesen Sie mehr über das Versenden von E-Mails.

Nun kehren wir zum Presenter zurück und vervollständigen die Methode contactFormSucceeded(). Sie ruft die Methode sendMessage() der Klasse ContactFacade auf und übergibt ihr die Formulardaten. Und wie erhalten wir das ContactFacade Objekt? Wir lassen es uns vom Konstruktor übergeben:

use App\Model\ContactFacade;
use Nette\Application\UI\Form;
use Nette\Application\UI\Presenter;

class HomePresenter extends Presenter
{
	public function __construct(
		private ContactFacade $facade,
	) {
	}

	protected function createComponentContactForm(): Form
	{
		// ...
	}

	public function contactFormSucceeded(stdClass $data): void
	{
		$this->facade->sendMessage($data->email, $data->name, $data->message);
		$this->flashMessage('The message has been sent');
		$this->redirect('this');
	}
}

Nachdem die E-Mail versendet wurde, zeigen wir dem Benutzer die so genannte Flash-Nachricht an, die bestätigt, dass die Nachricht versendet wurde, und leiten dann zur nächsten Seite weiter, damit das Formular nicht mit refresh im Browser erneut abgeschickt werden kann.

Nun, wenn alles funktioniert, sollten Sie in der Lage sein, eine E-Mail über Ihr Kontaktformular zu versenden. Herzlichen Glückwunsch!

HTML-E-Mail-Vorlage

Im Moment wird eine einfache Text-E-Mail verschickt, die nur die vom Formular gesendete Nachricht enthält. Aber wir können HTML in der E-Mail verwenden und sie attraktiver gestalten. Wir werden dafür eine Vorlage in Latte erstellen, die wir unter app/Model/contactEmail.latte speichern werden:

<html>
	<title>Message from the contact form</title>

	<body>
		<p><strong>Name:</strong> {$name}</p>
		<p><strong>E-mail:</strong> {$email}</p>
		<p><strong>Message:</strong> {$message}</p>
	</body>
</html>

Es bleibt noch ContactFacade zu ändern, um diese Vorlage zu verwenden. Im Konstruktor fordern wir die Klasse LatteFactory an, die das Objekt Latte\Engine erzeugen kann, einen Latte-Vorlagen-Renderer. Wir verwenden die Methode renderToString(), um die Vorlage in eine Datei zu rendern; der erste Parameter ist der Pfad zur Vorlage und der zweite die Variablen.

namespace App\Model;

use Nette\Bridges\ApplicationLatte\LatteFactory;
use Nette\Mail\Mailer;
use Nette\Mail\Message;

class ContactFacade
{
	public function __construct(
		private Mailer $mailer,
		private LatteFactory $latteFactory,
	) {
	}

	public function sendMessage(string $email, string $name, string $message): void
	{
		$latte = $this->latteFactory->create();
		$body = $latte->renderToString(__DIR__ . '/contactEmail.latte', [
			'email' => $email,
			'name' => $name,
			'message' => $message,
		]);

		$mail = new Message;
		$mail->addTo('admin@example.com') // your email
			->setFrom($email, $name)
			->setHtmlBody($body);

		$this->mailer->send($mail);
	}
}

Anschließend übergeben wir die generierte HTML-E-Mail an die Methode setHtmlBody() anstelle der ursprünglichen setBody(). Wir müssen auch den Betreff der E-Mail in setSubject() nicht angeben, da die Bibliothek ihn aus dem Element <title> in der Vorlage übernimmt.

Konfigurieren von

Im Code der Klasse ContactFacade ist unsere Admin-E-Mail admin@example.com noch fest codiert. Es wäre besser, sie in die Konfigurationsdatei zu verschieben. Wie kann man das tun?

Zunächst ändern wir die Klasse ContactFacade und ersetzen den E-Mail-String durch eine Variable, die vom Konstruktor übergeben wird:

class ContactFacade
{
	public function __construct(
		private Mailer $mailer,
		private LatteFactory $latteFactory,
		private string $adminEmail,
	) {
	}

	public function sendMessage(string $email, string $name, string $message): void
	{
		// ...
		$mail = new Message;
		$mail->addTo($this->adminEmail)
			->setFrom($email, $name)
			->setHtmlBody($body);
		// ...
	}
}

Der zweite Schritt besteht darin, den Wert dieser Variable in die Konfiguration aufzunehmen. In der Datei app/config/services.neon fügen wir hinzu:

services:
	- App\Model\ContactFacade(adminEmail: admin@example.com)

Und das war's. Wenn es viele Einträge im Abschnitt services gibt und Sie das Gefühl haben, dass die E-Mail unter den Einträgen verloren geht, können wir sie zu einer Variablen machen. Wir ändern den Eintrag in:

services:
	- App\Model\ContactFacade(adminEmail: %adminEmail%)

Und definieren diese Variable in der Datei app/config/common.neon:

parameters:
	adminEmail: admin@example.com

Und schon ist es geschafft!