/
in-presenter.texy
433 lines (307 loc) · 21.9 KB
/
in-presenter.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
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
Formulare in Moderatoren
************************
.[perex]
Nette Forms erleichtert die Erstellung und Bearbeitung von Webformularen erheblich. In diesem Kapitel lernen Sie, wie Sie Formulare in Presentern verwenden können.
Wenn Sie daran interessiert sind, sie völlig eigenständig ohne den Rest des Frameworks zu verwenden, gibt es eine Anleitung für [eigenständige Formulare |standalone].
Erstes Formular .[#toc-first-form]
==================================
Wir werden versuchen, ein einfaches Registrierungsformular zu schreiben. Sein Code wird wie folgt aussehen:
```php
use Nette\Application\UI\Form;
$form = new Form;
$form->addText('name', 'Name:');
$form->addPassword('password', 'Password:');
$form->addSubmit('send', 'Sign up');
$form->onSuccess[] = [$this, 'formSucceeded'];
```
und im Browser sollte das Ergebnis wie folgt aussehen:
[* form-en.webp *]
Das Formular im Presenter ist ein Objekt der Klasse `Nette\Application\UI\Form`, sein Vorgänger `Nette\Forms\Form` ist für den eigenständigen Gebrauch gedacht. Wir haben ihm die Felder Name, Passwort und Sendebutton hinzugefügt. Schließlich besagt die Zeile mit `$form->onSuccess`, dass nach dem Absenden und der erfolgreichen Validierung die Methode `$this->formSucceeded()` aufgerufen werden soll.
Aus der Sicht des Präsentators ist das Formular eine gemeinsame Komponente. Daher wird es als Komponente behandelt und mit der [Factory-Methode |application:components#Factory Methods] in den Presenter eingebunden. Das sieht dann wie folgt aus:
```php .{file:app/UI/Home/HomePresenter.php}
use Nette;
use Nette\Application\UI\Form;
class HomePresenter extends Nette\Application\UI\Presenter
{
protected function createComponentRegistrationForm(): Form
{
$form = new Form;
$form->addText('name', 'Name:');
$form->addPassword('password', 'Password:');
$form->addSubmit('send', 'Sign up');
$form->onSuccess[] = [$this, 'formSucceeded'];
return $form;
}
public function formSucceeded(Form $form, $data): void
{
// hier werden die vom Formular gesendeten Daten verarbeitet
// $data->name enthält Name
// $data->password enthält das Passwort
$this->flashMessage('Sie haben sich erfolgreich angemeldet.');
$this->redirect('Home:');
}
}
```
Und das Rendern in der Vorlage erfolgt mit dem Tag `{control}`:
```latte .{file:app/UI/Home/default.latte}
<h1>Registration</h1>
{control registrationForm}
```
Und das ist alles :-) Wir haben ein funktionierendes und perfekt [gesichertes |#Vulnerability Protection] Formular.
Jetzt denken Sie wahrscheinlich, dass es zu schnell ging und fragen sich, wie es möglich ist, dass die Methode `formSucceeded()` aufgerufen wird und welche Parameter sie erhält. Sicher, Sie haben Recht, das verdient eine Erklärung.
Nette hat sich einen coolen Mechanismus einfallen lassen, den wir [Hollywood-Stil |application:components#Hollywood style] nennen. Anstatt ständig nachzufragen, ob etwas passiert ist ("wurde das Formular abgeschickt?", "wurde es gültig abgeschickt?" oder "wurde es nicht gefälscht?"), sagt man dem Framework "wenn das Formular gültig ausgefüllt ist, rufe diese Methode auf" und lässt es weiterarbeiten. Wenn Sie in JavaScript programmieren, sind Sie mit dieser Art der Programmierung vertraut. Sie schreiben Funktionen, die aufgerufen werden, wenn ein bestimmtes [Ereignis |nette:glossary#Events] eintritt. Und die Sprache übergibt die entsprechenden Argumente an sie.
So ist der obige Presenter-Code aufgebaut. Das Array `$form->onSuccess` stellt die Liste der PHP-Rückrufe dar, die Nette aufruft, wenn das Formular eingereicht und korrekt ausgefüllt wurde.
Im [Lebenszyklus des Presenters |application:presenters#Life Cycle of Presenter] handelt es sich um ein so genanntes Signal, das heißt, sie werden nach der Methode `action*` und vor der Methode `render*` aufgerufen.
Und es übergibt jedem Callback im ersten Parameter das Formular selbst und im zweiten Parameter die gesendeten Daten als Objekt [ArrayHash |utils:arrays#ArrayHash]. Sie können den ersten Parameter weglassen, wenn Sie das Formularobjekt nicht benötigen. Der zweite Parameter kann sogar noch praktischer sein, aber dazu [später |#Mapping to Classes] mehr.
Das Objekt `$data` enthält die Eigenschaften `name` und `password` mit den vom Benutzer eingegebenen Daten. Normalerweise senden wir die Daten direkt zur weiteren Verarbeitung, z. B. zum Einfügen in die Datenbank. Es kann jedoch ein Fehler bei der Verarbeitung auftreten, z. B. wenn der Benutzername bereits vergeben ist. In diesem Fall geben wir den Fehler mit `addError()` an das Formular zurück und lassen es neu zeichnen, mit einer Fehlermeldung:
```php
$form->addError('Sorry, username is already in use.');
```
Neben `onSuccess` gibt es auch `onSubmit`: Callbacks werden immer nach dem Absenden des Formulars aufgerufen, auch wenn es nicht korrekt ausgefüllt ist. Und schließlich `onError`: Rückrufe werden nur aufgerufen, wenn die Übermittlung nicht gültig ist. Sie werden sogar aufgerufen, wenn wir das Formular in `onSuccess` oder `onSubmit` mit `addError()` ungültig machen.
Nach der Bearbeitung des Formulars werden wir zur nächsten Seite weiterleiten. Dadurch wird verhindert, dass das Formular unbeabsichtigt durch Anklicken des *Refresh*- oder *Back*-Buttons oder durch Verschieben des Browserverlaufs erneut abgeschickt wird.
Versuchen Sie, weitere [Formularsteuerelemente |controls] hinzuzufügen.
Zugang zu Steuerelementen .[#toc-access-to-controls]
====================================================
Das Formular ist eine Komponente des Presenters, in unserem Fall mit dem Namen `registrationForm` (nach dem Namen der Factory-Methode `createComponentRegistrationForm`), so dass Sie von jeder Stelle des Presenters aus auf das Formular zugreifen können:
```php
$form = $this->getComponent('registrationForm');
// alternative Syntax: $form = $this['registrationForm'];
```
Auch die einzelnen Steuerelemente des Formulars sind Komponenten, so dass Sie auf sie auf die gleiche Weise zugreifen können:
```php
$input = $form->getComponent('name'); // oder $input = $form['name'];
$button = $form->getComponent('send'); // oder $button = $form['send'];
```
Steuerelemente werden mit unset entfernt:
```php
unset($form['name']);
```
Überprüfungsregeln .[#toc-validation-rules]
===========================================
Das Wort *valid* wurde mehrere Male verwendet, aber das Formular hat noch keine Validierungsregeln. Das müssen wir ändern.
Der Name wird obligatorisch sein, also werden wir ihn mit der Methode `setRequired()` markieren, deren Argument der Text der Fehlermeldung ist, die angezeigt wird, wenn der Benutzer sie nicht ausfüllt. Wenn kein Argument angegeben wird, wird die Standard-Fehlermeldung verwendet.
```php
$form->addText('name', 'Name:')
->setRequired('Please fill your name.');
```
Versuchen Sie, das Formular abzuschicken, ohne den Namen auszufüllen, und Sie werden sehen, dass eine Fehlermeldung angezeigt wird und der Browser oder Server das Formular ablehnt, bis Sie es ausgefüllt haben.
Gleichzeitig können Sie das System nicht austricksen, indem Sie z. B. nur Leerzeichen in die Eingabe eintippen. Das geht nicht. Nette schneidet automatisch linke und rechte Leerzeichen ab. Probieren Sie es aus. Das sollten Sie bei jeder einzeiligen Eingabe immer tun, aber das wird oft vergessen. Nette macht es automatisch. (Sie können versuchen, die Formulare zu täuschen und eine mehrzeilige Zeichenkette als Namen zu senden. Auch hier lässt sich Nette nicht täuschen und die Zeilenumbrüche werden in Leerzeichen umgewandelt.)
Das Formular wird immer serverseitig validiert, aber es wird auch eine JavaScript-Validierung generiert, die schnell ist und dem Benutzer den Fehler sofort anzeigt, ohne dass das Formular an den Server gesendet werden muss. Dies wird durch das Skript `netteForms.js` erledigt.
Fügen Sie es in die Layout-Vorlage ein:
```latte
<script src="https://unpkg.com/nette-forms@3/src/assets/netteForms.js"></script>
```
Wenn Sie in den Quellcode der Seite mit dem Formular schauen, werden Sie feststellen, dass Nette die erforderlichen Felder in Elemente mit einer CSS-Klasse `required` einfügt. Versuchen Sie, den folgenden Stil in die Vorlage einzufügen, und die Bezeichnung "Name" wird rot sein. Auf elegante Weise markieren wir die erforderlichen Felder für die Benutzer:
```latte
<style>
.required label { color: maroon }
</style>
```
Zusätzliche Validierungsregeln werden mit der Methode `addRule()` hinzugefügt. Der erste Parameter ist rule, der zweite ist wieder der Text der Fehlermeldung, und das optionale Argument validation rule kann folgen. Was bedeutet das?
Das Formular erhält eine weitere optionale Eingabe *Alter* mit der Bedingung, dass es eine Zahl sein muss (`addInteger()`) und in bestimmten Grenzen (`$form::Range`). Und hier werden wir das dritte Argument von `addRule()` verwenden, den Bereich selbst:
```php
$form->addInteger('age', 'Age:')
->addRule($form::Range, 'You must be older 18 years and be under 120.', [18, 120]);
```
.[tip]
Wenn der Benutzer das Feld nicht ausfüllt, werden die Validierungsregeln nicht überprüft, da das Feld optional ist.
Offensichtlich ist Raum für ein kleines Refactoring vorhanden. In der Fehlermeldung und im dritten Parameter sind die Zahlen doppelt aufgeführt, was nicht ideal ist. Wenn wir ein [mehrsprachiges Formular |rendering#translating] erstellen würden und die Nachricht mit den Zahlen in mehrere Sprachen übersetzt werden müsste, würde dies die Änderung der Werte erschweren. Aus diesem Grund können die Ersatzzeichen `%d` verwendet werden:
```php
->addRule($form::Range, 'You must be older %d years and be under %d.', [18, 120]);
```
Kehren wir zum Feld *Kennwort* zurück, machen es *erforderlich* und überprüfen die Mindestlänge des Kennworts (`$form::MinLength`), wiederum unter Verwendung der Ersatzzeichen in der Nachricht:
```php
$form->addPassword('password', 'Password:')
->setRequired('Pick a password')
->addRule($form::MinLength, 'Your password has to be at least %d long', 8);
```
Wir fügen dem Formular ein Feld `passwordVerify` hinzu, in das der Benutzer das Passwort erneut eingibt, um es zu überprüfen. Mit Hilfe von Validierungsregeln überprüfen wir, ob beide Passwörter gleich sind (`$form::Equal`). Und als Argument geben wir in [eckigen Klammern |#Access to Controls] einen Verweis auf das erste Kennwort an:
```php
$form->addPassword('passwordVerify', 'Password again:')
->setRequired('Fill your password again to check for typo')
->addRule($form::Equal, 'Password mismatch', $form['password'])
->setOmitted();
```
Mit `setOmitted()` markieren wir ein Element, dessen Wert uns nicht wirklich interessiert und das nur zur Validierung existiert. Sein Wert wird nicht an `$data` übergeben.
Wir haben ein voll funktionsfähiges Formular mit Validierung in PHP und JavaScript. Die Validierungsmöglichkeiten von Nette sind viel umfassender, Sie können Bedingungen erstellen, Teile einer Seite entsprechend anzeigen und ausblenden usw. Sie können alles im Kapitel über [Formularvalidierung |validation] nachlesen.
Standardwerte .[#toc-default-values]
====================================
Wir setzen oft Standardwerte für Formularsteuerelemente:
```php
$form->addEmail('email', 'Email')
->setDefaultValue($lastUsedEmail);
```
Oft ist es sinnvoll, Standardwerte für alle Steuerelemente gleichzeitig festzulegen. Zum Beispiel, wenn das Formular verwendet wird, um Datensätze zu bearbeiten. Wir lesen den Datensatz aus der Datenbank und legen ihn als Standardwerte fest:
```php
//$row = ['name' => 'John', 'age' => '33', /* ... */];
$form->setDefaults($row);
```
Rufen Sie `setDefaults()` auf, nachdem Sie die Steuerelemente definiert haben.
Rendering des Formulars .[#toc-rendering-the-form]
==================================================
Standardmäßig wird das Formular als Tabelle gerendert. Die einzelnen Steuerelemente entsprechen den grundlegenden Richtlinien für die Barrierefreiheit im Web. Alle Beschriftungen werden als `<label>` Elemente generiert und sind mit ihren Eingaben verknüpft; ein Klick auf die Beschriftung bewegt den Cursor auf die Eingabe.
Wir können für jedes Element beliebige HTML-Attribute festlegen. Fügen Sie zum Beispiel einen Platzhalter hinzu:
```php
$form->addInteger('age', 'Age:')
->setHtmlAttribute('placeholder', 'Please fill in the age');
```
Es gibt wirklich viele Möglichkeiten, ein Formular zu rendern, daher ist dieses Kapitel dem [Rendering |rendering] gewidmet.
Mapping auf Klassen .[#toc-mapping-to-classes]
==============================================
Kehren wir zur Methode `formSucceeded()` zurück, die im zweiten Parameter `$data` die gesendeten Daten als `ArrayHash` Objekt erhält. Da es sich hierbei um eine generische Klasse handelt, ähnlich wie `stdClass`, fehlen uns einige Annehmlichkeiten bei der Arbeit mit ihr, wie z. B. die Codevervollständigung für Eigenschaften in Editoren oder die statische Codeanalyse. Dies könnte durch eine spezifische Klasse für jedes Formular gelöst werden, deren Eigenschaften die einzelnen Steuerelemente darstellen. Z.B.:
```php
class RegistrationFormData
{
public string $name;
public int $age;
public string $password;
}
```
Ab PHP 8.0 können Sie diese elegante Notation verwenden, die einen Konstruktor benutzt:
```php
class RegistrationFormData
{
public function __construct(
public string $name,
public int $age,
public string $password,
) {
}
}
```
Wie sagt man Nette, dass es Daten als Objekte dieser Klasse zurückgeben soll? Einfacher als Sie denken. Alles, was Sie tun müssen, ist, die Klasse als Typ des `$data` Parameters im Handler anzugeben:
```php
public function formSucceeded(Form $form, RegistrationFormData $data): void
{
// $name ist eine Instanz von RegistrationFormData
$name = $data->name;
// ...
}
```
Sie können auch `array` als Typ angeben, dann werden die Daten als Array übergeben.
In ähnlicher Weise können Sie die Methode `getValues()` verwenden, die wir als Klassenname oder Objekt an hydrate als Parameter übergeben:
```php
$data = $form->getValues(RegistrationFormData::class);
$name = $data->name;
```
Wenn die Formulare aus einer mehrstufigen Struktur bestehen, die sich aus Containern zusammensetzt, erstellen Sie für jeden Container eine eigene Klasse:
```php
$form = new Form;
$person = $form->addContainer('person');
$person->addText('firstName');
/* ... */
class PersonFormData
{
public string $firstName;
public string $lastName;
}
class RegistrationFormData
{
public PersonFormData $person;
public int $age;
public string $password;
}
```
Das Mapping weiß dann anhand des Eigenschaftstyps `$person`, dass es den Container auf die Klasse `PersonFormData` abbilden soll. Wenn die Eigenschaft ein Array von Containern enthalten würde, geben Sie den Typ `array` an und übergeben Sie die Klasse, die direkt auf den Container abgebildet werden soll:
```php
$person->setMappedType(PersonFormData::class);
```
Mit der Methode `Nette\Forms\Blueprint::dataClass($form)` können Sie einen Vorschlag für die Datenklasse eines Formulars erzeugen, der auf der Browserseite ausgedruckt wird. Sie können dann einfach auf den Code klicken, um ihn auszuwählen und in Ihr Projekt zu kopieren. .{data-version:3.1.15}
Mehrere Submit-Buttons .[#toc-multiple-submit-buttons]
======================================================
Wenn das Formular mehr als eine Schaltfläche hat, müssen wir normalerweise unterscheiden, welche Schaltfläche gedrückt wurde. Wir können für jede Schaltfläche eine eigene Funktion erstellen. Legen Sie sie als Handler für das [Ereignis |nette:glossary#Events] `onClick` fest:
```php
$form->addSubmit('save', 'Save')
->onClick[] = [$this, 'saveButtonPressed'];
$form->addSubmit('delete', 'Delete')
->onClick[] = [$this, 'deleteButtonPressed'];
```
Diese Handler werden auch nur dann aufgerufen, wenn das Formular gültig ist, wie im Fall des Ereignisses `onSuccess`. Der Unterschied besteht darin, dass der erste Parameter das Submit-Button-Objekt anstelle des Formulars sein kann, je nachdem, welchen Typ Sie angeben:
```php
public function saveButtonPressed(Nette\Forms\Controls\Button $button, $data)
{
$form = $button->getForm();
// ...
}
```
Wenn ein Formular mit der <kbd>Eingabetaste</kbd> abgeschickt wird, wird es so behandelt, als ob es mit der ersten Schaltfläche abgeschickt worden wäre.
Ereignis onAnchor .[#toc-event-onanchor]
========================================
Wenn Sie ein Formular in einer Factory-Methode (wie `createComponentRegistrationForm`) erstellen, weiß es noch nicht, ob es abgeschickt wurde oder mit welchen Daten es abgeschickt wurde. Aber es gibt Fälle, in denen wir die übermittelten Werte kennen müssen, vielleicht hängt es von ihnen ab, wie das Formular aussehen wird, oder sie werden für abhängige Auswahlfelder verwendet usw.
Daher kann der Code, der das Formular erstellt, aufgerufen werden, wenn es verankert ist, d.h. wenn es bereits mit dem Präsentator verknüpft ist und die übermittelten Daten kennt. Wir werden diesen Code in das Array `$onAnchor` einfügen:
```php
$country = $form->addSelect('country', 'Country:', $this->model->getCountries());
$city = $form->addSelect('city', 'City:');
$form->onAnchor[] = function () use ($country, $city) {
// diese Funktion wird aufgerufen, wenn das Formular weiß, dass es mit Daten gesendet wurde
// damit Sie die Methode getValue() verwenden können
$val = $country->getValue();
$city->setItems($val ? $this->model->getCities($val) : []);
};
```
Schutz vor Schwachstellen .[#toc-vulnerability-protection]
==========================================================
Nette Framework gibt sich große Mühe, sicher zu sein, und da Formulare die häufigste Benutzereingabe sind, sind Nette-Formulare so gut wie unangreifbar. Alles wird dynamisch und transparent verwaltet, nichts muss manuell eingestellt werden.
Zusätzlich zum Schutz der Formulare vor Angriffen auf bekannte Schwachstellen wie [Cross-Site Scripting (XSS) |nette:glossary#cross-site-scripting-xss] und [Cross-Site Request Forgery (CSRF |nette:glossary#cross-site-request-forgery-csrf]) übernimmt es viele kleine Sicherheitsaufgaben, an die Sie nicht mehr denken müssen.
So filtert es zum Beispiel alle Steuerzeichen aus den Eingaben heraus und überprüft die Gültigkeit der UTF-8-Kodierung, so dass die Daten aus dem Formular immer sauber sind. Bei Auswahlfeldern und Auswahllisten wird überprüft, ob die ausgewählten Elemente tatsächlich aus den angebotenen ausgewählt wurden und keine Fälschung vorliegt. Wie bereits erwähnt, werden bei einzeiligen Texteingaben Zeichen am Zeilenende entfernt, die ein Angreifer dort einfügen könnte. Bei mehrzeiligen Eingaben werden die Zeichen am Zeilenende normalisiert. Und so weiter.
Nette behebt für Sie Sicherheitslücken, von deren Existenz die meisten Programmierer keine Ahnung haben.
Der erwähnte CSRF-Angriff besteht darin, dass ein Angreifer das Opfer dazu verleitet, eine Seite zu besuchen, die im Browser des Opfers unbemerkt eine Anfrage an den Server ausführt, bei dem das Opfer gerade angemeldet ist, und der Server glaubt, dass die Anfrage vom Opfer absichtlich gestellt wurde. Daher verhindert Nette, dass das Formular per POST von einer anderen Domäne übermittelt wird. Wenn Sie aus irgendeinem Grund den Schutz ausschalten und die Übermittlung des Formulars von einer anderen Domäne aus zulassen möchten, verwenden Sie:
```php
$form->allowCrossOrigin(); // ACHTUNG! Schaltet den Schutz aus!
```
Dieser Schutz verwendet ein SameSite-Cookie namens `_nss`. Der SameSite-Cookie-Schutz ist möglicherweise nicht zu 100 % zuverlässig, weshalb es ratsam ist, den Token-Schutz zu aktivieren:
```php
$form->addProtection();
```
Es wird dringend empfohlen, diesen Schutz auf die Formulare in einem administrativen Teil Ihrer Anwendung anzuwenden, in dem sensible Daten geändert werden. Das Framework schützt vor einem CSRF-Angriff, indem es ein Authentifizierungs-Token generiert und validiert, das in einer Session gespeichert wird (das Argument ist die Fehlermeldung, die angezeigt wird, wenn das Token abgelaufen ist). Aus diesem Grund muss vor der Anzeige des Formulars eine Session gestartet werden. Im Verwaltungsteil der Website ist die Session in der Regel bereits durch die Anmeldung des Benutzers gestartet.
Ansonsten starten Sie die Session mit der Methode `Nette\Http\Session::start()`.
Ein Formular in mehreren Presentern verwenden .[#toc-using-one-form-in-multiple-presenters]
===========================================================================================
Wenn Sie ein Formular in mehreren Presentern verwenden müssen, empfehlen wir Ihnen, eine Factory dafür zu erstellen, die Sie dann an den Presenter weitergeben. Ein geeigneter Ort für eine solche Klasse ist z. B. das Verzeichnis `app/Forms`.
Die Fabrikklasse könnte wie folgt aussehen:
```php
use Nette\Application\UI\Form;
class SignInFormFactory
{
public function create(): Form
{
$form = new Form;
$form->addText('name', 'Name:');
$form->addSubmit('send', 'Log in');
return $form;
}
}
```
Wir bitten die Klasse, das Formular in der Factory-Methode für Komponenten im Presenter zu erstellen:
```php
public function __construct(
private SignInFormFactory $formFactory,
) {
}
protected function createComponentSignInForm(): Form
{
$form = $this->formFactory->create();
// können wir das Formular ändern, hier zum Beispiel ändern wir die Beschriftung der Schaltfläche
$form['login']->setCaption('Continue');
$form->onSuccess[] = [$this, 'signInFormSubmitted']; // und fügen den Handler
return $form;
}
```
Der Handler für die Formularverarbeitung kann auch von der Fabrik geliefert werden:
```php
use Nette\Application\UI\Form;
class SignInFormFactory
{
public function create(): Form
{
$form = new Form;
$form->addText('name', 'Name:');
$form->addSubmit('send', 'Anmelden');
$form->onSuccess[] = function (Form $form, $data): void {
// wir bearbeiten unser eingereichtes Formular hier
};
return $form;
}
}
```
So, das war eine kurze Einführung in Formulare in Nette. Schauen Sie im Verzeichnis [examples |https://github.com/nette/forms/tree/master/examples] in der Distribution nach, um weitere Anregungen zu erhalten.