/
creating-editing-form.texy
206 lines (157 loc) · 6.11 KB
/
creating-editing-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
Formular zum Erstellen und Bearbeiten eines Datensatzes
*******************************************************
.[perex]
Wie kann man das Hinzufügen und Bearbeiten eines Datensatzes in Nette richtig umsetzen, indem man für beides das gleiche Formular verwendet?
In vielen Fällen sind die Formulare zum Hinzufügen und Bearbeiten eines Datensatzes identisch und unterscheiden sich nur durch die Beschriftung der Schaltfläche. Wir werden Beispiele für einfache Präsentationen zeigen, bei denen wir das Formular zuerst zum Hinzufügen eines Datensatzes und dann zum Bearbeiten verwenden und schließlich beide Lösungen kombinieren.
Hinzufügen eines Datensatzes .[#toc-adding-a-record]
----------------------------------------------------
Ein Beispiel für einen Präsentator, der zum Hinzufügen eines Datensatzes verwendet wird. Die eigentliche Datenbankarbeit überlassen wir der Klasse `Facade`, deren Code für dieses Beispiel nicht relevant ist.
```php
use Nette\Application\UI\Form;
class RecordPresenter extends Nette\Application\UI\Presenter
{
public function __construct(
private Facade $facade,
) {
}
protected function createComponentRecordForm(): Form
{
$form = new Form;
// ... Formularfelder hinzufügen ...
$form->onSuccess[] = [$this, 'recordFormSucceeded'];
return $form;
}
public function recordFormSucceeded(Form $form, array $data): void
{
$this->facade->add($data); // Datensatz zur Datenbank hinzufügen
$this->flashMessage("Erfolgreich hinzugefügt");
$this->redirect('...');
}
public function renderAdd(): void
{
// ...
}
}
```
Bearbeiten eines Datensatzes .[#toc-editing-a-record]
-----------------------------------------------------
Sehen wir uns nun an, wie ein Presenter zum Bearbeiten eines Datensatzes aussehen würde:
```php
use Nette\Application\UI\Form;
class RecordPresenter extends Nette\Application\UI\Presenter
{
private $record;
public function __construct(
private Facade $facade,
) {
}
public function actionEdit(int $id): void
{
$record = $this->facade->get($id);
if (
!$record // die Existenz des Datensatzes zu überprüfen
|| !$this->facade->isEditAllowed(/*...*/) // Berechtigungen prüfen
) {
$this->error(); // 404-Fehler
}
$this->record = $record;
}
protected function createComponentRecordForm(): Form
{
// Überprüfen, ob die Aktion "Bearbeiten" ist
if ($this->getAction() !== 'edit') {
$this->error();
}
$form = new Form;
// ... Formularfelder hinzufügen ...
$form->setDefaults($this->record); // Standardwerte setzen
$form->onSuccess[] = [$this, 'recordFormSucceeded'];
return $form;
}
public function recordFormSucceeded(Form $form, array $data): void
{
$this->facade->update($this->record->id, $data); // Datensatz aktualisieren
$this->flashMessage("Erfolgreich aktualisiert");
$this->redirect('...');
}
}
```
In der *Action*-Methode, die gleich zu Beginn des [Presenter-Lebenszyklus |application:presenters#Life Cycle of Presenter] aufgerufen wird, überprüfen wir die Existenz des Datensatzes und die Berechtigung des Benutzers, ihn zu bearbeiten.
Wir speichern den Datensatz in der Eigenschaft `$record`, so dass er in der Methode `createComponentRecordForm()` zum Festlegen von Standardwerten und `recordFormSucceeded()` für die ID zur Verfügung steht. Eine alternative Lösung wäre, die Standardwerte direkt in `actionEdit()` zu setzen und den ID-Wert, der Teil der URL ist, mit `getParameter('id')` abzurufen:
```php
public function actionEdit(int $id): void
{
$record = $this->facade->get($id);
if (
// Existenz überprüfen und Berechtigungen prüfen
) {
$this->error();
}
// Standardwerte für das Formular festlegen
$this->getComponent('recordForm')
->setDefaults($record);
}
public function recordFormSucceeded(Form $form, array $data): void
{
$id = (int) $this->getParameter('id');
$this->facade->update($id, $data);
// ...
}
}
```
Allerdings, und das sollte **die wichtigste Erkenntnis aus dem ganzen Code** sein, müssen wir sicherstellen, dass die Aktion tatsächlich `edit` ist, wenn wir das Formular erstellen. Denn sonst würde die Validierung in der Methode `actionEdit()` überhaupt nicht stattfinden!
Dasselbe Formular zum Hinzufügen und Bearbeiten .[#toc-same-form-for-adding-and-editing]
----------------------------------------------------------------------------------------
Und nun werden wir beide Präsentatoren in einem kombinieren. Entweder wir unterscheiden, welche Aktion an der Methode `createComponentRecordForm()` beteiligt ist und konfigurieren das Formular entsprechend, oder wir überlassen es direkt den Aktionsmethoden und lassen die Bedingung weg:
```php
class RecordPresenter extends Nette\Application\UI\Presenter
{
public function __construct(
private Facade $facade,
) {
}
public function actionAdd(): void
{
$form = $this->getComponent('recordForm');
$form->onSuccess[] = [$this, 'addingFormSucceeded'];
}
public function actionEdit(int $id): void
{
$record = $this->facade->get($id);
if (
!$record // die Existenz des Datensatzes zu überprüfen
|| !$this->facade->isEditAllowed(/*...*/) // Berechtigungen prüfen
) {
$this->error(); // 404-Fehler
}
$form = $this->getComponent('recordForm');
$form->setDefaults($record); // Standardeinstellungen festlegen
$form->onSuccess[] = [$this, 'editingFormSucceeded'];
}
protected function createComponentRecordForm(): Form
{
// Überprüfen, ob die Aktion "Hinzufügen" oder "Bearbeiten" ist
if (!in_array($this->getAction(), ['add', 'edit'])) {
$this->error();
}
$form = new Form;
// ... Formularfelder hinzufügen ...
return $form;
}
public function addingFormSucceeded(Form $form, array $data): void
{
$this->facade->add($data); // Datensatz zur Datenbank hinzufügen
$this->flashMessage("Erfolgreich hinzugefügt");
$this->redirect('...');
}
public function editingFormSucceeded(Form $form, array $data): void
{
$id = (int) $this->getParameter('id');
$this->facade->update($id, $data); // Datensatz aktualisieren
$this->flashMessage("Erfolgreich aktualisiert");
$this->redirect('...');
}
}
```
{{priority: -1}}
{{sitename: Bewährte Praktiken}}