/
lets-create-contact-form.texy
226 lines (173 loc) · 7.87 KB
/
lets-create-contact-form.texy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
Erstellen wir ein Kontakt-Formular
**********************************
.[perex]
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" |nette:installation] erklärt wird. Und dann können wir mit der Erstellung des Formulars beginnen.
Der einfachste Weg ist, das [Formular direkt in Presenter |forms: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:
```php
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 |nette:glossary#events] `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 `Home/default.latte` gerendert werden:
```latte
{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
<?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 |mail:].
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:
```php
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 |application:components#flash-messages] 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 .[#toc-html-email-template]
-----------------------------------------------
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:
```latte
<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 |latte:develop#how-to-render-a-template]. 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.
```php
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 .[#toc-configuring]
-------------------------------------
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:
```php
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:
```neon
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:
```neon
services:
- App\Model\ContactFacade(adminEmail: %adminEmail%)
```
Und definieren diese Variable in der Datei `app/config/common.neon`:
```neon
parameters:
adminEmail: admin@example.com
```
Und schon ist es geschafft!
{{sitename: Bewährte Praktiken}}