Erstellen wir ein Kontaktformular
Sehen wir uns an, wie man in Nette ein Kontaktformular erstellt, einschließlich des Versands der übermittelten Daten per E-Mail. Also los!
Zuerst müssen wir ein neues Projekt anlegen. Wie das geht, erklärt die Seite Erste Schritte. Und dann können wir mit der Erstellung des Formulars beginnen.
Am einfachsten ist es, das Formular direkt im Presenter zu erstellen.
Wir können den bereits vorhandenen HomePresenter verwenden. Wir fügen ihm eine Komponente contactForm
hinzu, die das Formular darstellt. Das erreichen wir, indem wir in den Code die Factory-Methode
createComponentContactForm() schreiben, die 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('Bitte geben Sie Ihren Namen ein');
$form->addEmail('email', 'E-Mail:')
->setRequired('Bitte geben Sie Ihre E-Mail-Adresse ein');
$form->addTextArea('message', 'Nachricht:')
->setRequired('Bitte geben Sie eine Nachricht ein');
$form->addSubmit('send', 'Senden');
$form->onSuccess[] = $this->contactFormSucceeded(...);
return $form;
}
private function contactFormSucceeded(Form $form, $data): void
{
// Versand der E-Mail
}
}
Wie Sie sehen, haben wir zwei Methoden erstellt. Die erste Methode, createComponentContactForm(), erzeugt eine
neue Formularinstanz. Sie enthält Felder für Name, E-Mail und Nachricht, die wir mit den Methoden addText(),
addEmail() und addTextArea() hinzufügen. Außerdem haben wir eine Schaltfläche zum Absenden ergänzt.
Aber was, wenn der Benutzer ein Feld leer lässt? In diesem Fall sollten wir ihm mitteilen, dass es sich um ein Pflichtfeld
handelt. Das haben wir mit der Methode setRequired() erreicht. Schließlich haben wir noch einen Handler für das Event onSuccess angehängt, der beim erfolgreichen Absenden
des Formulars ausgelöst wird. In unserem Fall ruft er die Methode contactFormSucceeded auf, die sich um die
Verarbeitung der übermittelten Daten kümmert. Diese Methode ergänzen wir gleich.
Die Komponente contactForm lassen wir im Template Home/default.latte rendern:
{block content}
<h1>Kontaktformular</h1>
{control contactForm}
Für den eigentlichen Versand der E-Mail erstellen wir eine neue Klasse mit dem Namen ContactFacade und legen sie
in der Datei app/Model/ContactFacade.php ab:
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') // Ihre E-Mail-Adresse
->setFrom($email, $name)
->setSubject('Nachricht aus dem Kontaktformular')
->setBody($message);
$this->mailer->send($mail);
}
}
Die Methode sendMessage() erstellt und versendet die E-Mail. Sie nutzt dazu einen Mailer, den sie sich als
Abhängigkeit über den Konstruktor übergeben lässt. 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 über das Formular gesendeten
Daten. Und wie bekommen wir das Objekt ContactFacade? Wir lassen es uns über den 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('Die Nachricht wurde gesendet');
$this->redirect('this');
}
}
Nachdem die E-Mail versendet wurde, zeigen wir dem Benutzer noch eine Flash-Meldung, die den Versand bestätigt. Danach leiten wir weiter, damit das Formular nicht durch ein Refresh im Browser erneut abgeschickt werden kann.
So, und wenn alles richtig eingerichtet ist, sollten Sie nun eine E-Mail aus Ihrem Kontaktformular versenden können. Herzlichen Glückwunsch!
HTML-Template für E-Mails
Bisher wird eine einfache Text-E-Mail versendet, die nur die über das Formular gesendete Nachricht enthält. In der E-Mail
können wir aber HTML verwenden und ihr Aussehen ansprechender gestalten. Wir erstellen dafür ein Template in Latte, das wir
unter app/Model/contactEmail.latte speichern:
<html>
<title>Nachricht aus dem Kontaktformular</title>
<body>
<p><strong>Name:</strong> {$name}</p>
<p><strong>E-Mail:</strong> {$email}</p>
<p><strong>Nachricht:</strong> {$message}</p>
</body>
</html>
Es bleibt, ContactFacade so anzupassen, dass diese Vorlage verwendet wird. Im Konstruktor fordern wir die Klasse
LatteFactory an, die ein Objekt Latte\Engine erzeugen kann, also den Renderer für Latte-Templates. Mit der Methode
renderToString() rendern wir das Template in einen String; der erste Parameter ist der Pfad zur Template-Datei und
der zweite ein Array der zu übergebenden 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') // Ihre E-Mail-Adresse
->setFrom($email, $name)
->setHtmlBody($body);
$this->mailer->send($mail);
}
}
Den erzeugten HTML-Inhalt der E-Mail übergeben wir dann der Methode setHtmlBody() statt der ursprünglichen
setBody(). Ebenso müssen wir den Betreff der E-Mail nicht mehr mit setSubject() angeben, denn die
Bibliothek entnimmt ihn automatisch dem Element <title> des Templates.
Konfiguration
Im Code der Klasse ContactFacade steht immer noch fest verdrahtet unsere Administrator-E-Mail
admin@example.com. Besser wäre es, sie in die Konfigurationsdatei zu verschieben. Wie geht das?
Zuerst passen wir die Klasse ContactFacade an und ersetzen den fest verdrahteten E-Mail-String durch eine über
den Konstruktor übergebene Variable:
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 Variablen in der Konfiguration anzugeben. In die Datei
app/config/services.neon schreiben wir:
services:
- App\Model\ContactFacade(adminEmail: admin@example.com)
Und das war's. Wenn der Abschnitt services viele Einträge enthält und Sie das Gefühl haben, dass die
E-Mail-Adresse zwischen ihnen untergeht, können wir daraus einen Parameter machen. Wir ändern den Eintrag so:
services:
- App\Model\ContactFacade(adminEmail: %adminEmail%)
Und in der Datei app/config/common.neon definieren wir diesen Parameter:
parameters:
adminEmail: admin@example.com
Und fertig!