forked from nette/docs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathvalidation.texy
378 lines (270 loc) · 17.2 KB
/
validation.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
Convalida dei moduli
********************
Controlli richiesti .[#toc-required-controls]
=============================================
I controlli vengono contrassegnati come obbligatori con il metodo `setRequired()`, il cui argomento è il testo del [messaggio di errore |#Error Messages] che verrà visualizzato se l'utente non lo compila. Se non viene fornito alcun argomento, viene utilizzato il messaggio di errore predefinito.
```php
$form->addText('name', 'Name:')
->setRequired('Please fill your name.');
```
Regole .[#toc-rules]
====================
Con il metodo `addRule()` si aggiungono regole di convalida ai controlli. Il primo parametro è la regola, il secondo è il [messaggio di errore |#Error Messages] e il terzo è l'argomento della regola di validazione.
```php
$form->addPassword('password', 'Password:')
->addRule($form::MinLength, 'Password must be at least %d characters', 8);
```
**Le regole di validazione vengono controllate solo se l'utente ha compilato l'elemento **.
Nette dispone di una serie di regole predefinite i cui nomi sono costanti della classe `Nette\Forms\Form`. Possiamo applicare queste regole a tutti gli elementi:
| costante | descrizione | argomenti
|-------
| `Required` | alias di `setRequired()` | -
| `Filled` | alias di `setRequired()` | -
| `Blank` | non deve essere riempito | -
| `Equal` | il valore è uguale al parametro | `mixed`
| `NotEqual` | il valore non è uguale al parametro | `mixed`
| `IsIn` | il valore è uguale a qualche elemento dell'array | `array`
| `IsNotIn` | il valore non è uguale a nessun elemento dell'array | `array`
| `Valid` | l'input supera la convalida (per le [condizioni |#conditions]) | -
Ingressi di testo .[#toc-text-inputs]
-------------------------------------
Per gli elementi `addText()`, `addPassword()`, `addTextArea()`, `addEmail()`, `addInteger()`, `addFloat()` si possono applicare anche alcune delle seguenti regole:
| `MinLength` | lunghezza minima della stringa | `int`
| `MaxLength` | lunghezza massima della stringa | `int`
| `Length` | lunghezza nell'intervallo o lunghezza esatta | coppia `[int, int]` o `int`
| `Email` | indirizzo e-mail valido | -
| `URL` | URL valido | -
| `Pattern` | corrisponde al modello regolare | `string`
| `PatternInsensitive` | come `Pattern`, ma senza distinzione tra maiuscole e minuscole | `string`
| `Integer` | numero intero | -
| `Numeric` | pseudonimo di `Integer` | - -
| `Float` | numero intero o in virgola mobile | -
| `Min` | minimo del valore intero | `int\|float`
| `Max` | massimo del valore intero | `int\|float`
| `Range` | valore nell'intervallo | coppia `[int\|float, int\|float]`
Le regole `Integer`, `Numeric` e `Float` convertono automaticamente il valore in numero intero (o in virgola mobile, rispettivamente). Inoltre, la regola `URL` accetta anche un indirizzo senza schema (ad esempio `nette.org`) e completa lo schema (`https://nette.org`).
Le espressioni in `Pattern` e `PatternInsensitive` devono essere valide per l'intero valore, cioè come se fosse avvolto nei caratteri `^` and `$`.
Numero di articoli .[#toc-number-of-items]
------------------------------------------
Per gli elementi `addMultiUpload()`, `addCheckboxList()`, `addMultiSelect()` è possibile utilizzare anche le seguenti regole per limitare il numero di elementi selezionati o di file caricati:
| `MinLength` | numero minimo | `int`
| `MaxLength` | numero massimo | `int`
| `Length` | numero nell'intervallo o numero esatto | coppie `[int, int]` o `int`
Caricamento file
----------------
Per i controlli `addUpload()`, `addMultiUpload()` si possono utilizzare anche le seguenti regole:
| `MaxFileSize` | dimensione massima del file in byte | `int`
| `MimeType` | Tipo MIME, accetta caratteri jolly (`'video/*'`) | `string\|string[]`
| `Image` | il file caricato è JPEG, PNG, GIF, WebP | - - | il nome del file corrisponde a una regola regolare.
| `Pattern` | il nome del file corrisponde a un'espressione regolare | `string`
| `PatternInsensitive` | come `Pattern`, ma senza distinzione tra maiuscole e minuscole | `string`
`MimeType` e `Image` richiedono l'estensione PHP `fileinfo`. Il fatto che un file o un'immagine sia del tipo richiesto viene rilevato dalla sua firma. L'integrità dell'intero file non viene controllata. È possibile scoprire se un'immagine non è danneggiata, ad esempio provando a [caricarla |http:request#toImage].
Messaggi di errore .[#toc-error-messages]
=========================================
Tutte le regole predefinite, tranne `Pattern` e `PatternInsensitive`, hanno un messaggio di errore predefinito, quindi possono essere omesse. Tuttavia, passando e formulando tutti i messaggi personalizzati, si renderà il modulo più facile da usare.
È possibile modificare i messaggi predefiniti in [configuration |forms:configuration], modificando i testi dell'array `Nette\Forms\Validator::$messages` o utilizzando [il traduttore |rendering#translating].
I seguenti caratteri jolly possono essere usati nel testo dei messaggi di errore:
| `%d` | sostituisce gradualmente le regole dopo gli argomenti
| `%n$d` | sostituisce con l'argomento dell'ennesima regola
| `%label` | sostituisce l'etichetta del campo (senza i due punti)
| `%name` | sostituisce con il nome del campo (es. `name`)
| `%value` | sostituisce con il valore inserito dall'utente
```php
$form->addText('name', 'Name:')
->setRequired('Please fill in %label');
$form->addInteger('id', 'ID:')
->addRule($form::Range, 'at least %d and no more than %d', [5, 10]);
$form->addInteger('id', 'ID:')
->addRule($form::Range, 'no more than %2$d and at least %1$d', [5, 10]);
```
Condizioni .[#toc-conditions]
=============================
Oltre alle regole di validazione, è possibile impostare delle condizioni. Si impostano come le regole, ma si usa `addRule()` invece di `addCondition()` e, naturalmente, si lascia senza messaggio di errore (la condizione chiede solo):
```php
$form->addPassword('password', 'Password:')
// se la password non è più lunga di 8 caratteri ...
->addCondition($form::MaxLength, 8)
// ... allora deve contenere un numero
->addRule($form::Pattern, 'Deve contenere un numero', '.*[0-9].*');
```
La condizione può essere collegata a un elemento diverso da quello corrente usando `addConditionOn()`. Il primo parametro è un riferimento al campo. Nel caso seguente, l'e-mail sarà richiesta solo se la casella di controllo è selezionata (cioè il suo valore è `true`):
```php
$form->addCheckbox('newsletters', 'send me newsletters');
$form->addEmail('email', 'Email:')
// se la casella di controllo è selezionata ...
->addConditionOn($form['newsletters'], $form::Equal, true)
// ... richiede l'email
->setRequired('Inserisci il tuo indirizzo e-mail');
```
Le condizioni possono essere raggruppate in strutture complesse con i metodi `elseCondition()` e `endCondition()`.
```php
$form->addText(/* ... */)
->addCondition(/* ... */) // se la prima condizione è soddisfatta
->addConditionOn(/* ... */) // e la seconda condizione anche su un altro elemento
->addRule(/* ... */) // richiede questa regola
->elseCondition() // se la seconda condizione non è soddisfatta
->addRule(/* ... */) // richiede queste regole
->addRule(/* ... */)
->endCondition() // si torna alla prima condizione
->addRule(/* ... */);
```
In Nette, è molto facile reagire all'adempimento o meno di una condizione sul lato JavaScript, usando il metodo `toggle()`, vedere [JavaScript dinamico |#Dynamic JavaScript].
Riferimento a un altro elemento .[#toc-reference-to-another-element]
====================================================================
Come argomento per una regola o una condizione, si può passare anche un altro elemento del modulo. La regola utilizzerà il valore inserito successivamente dall'utente nel browser. Questo può essere utilizzato, ad esempio, per convalidare dinamicamente che l'elemento `password` contenga la stessa stringa dell'elemento `password_confirm`:
```php
$form->addPassword('password', 'Password');
$form->addPassword('password_confirm', 'Confirm Password')
->addRule($form::Equal, 'The passwords do not match', $form['password']);
```
Regole e condizioni personalizzate .[#toc-custom-rules-and-conditions]
======================================================================
A volte ci troviamo in una situazione in cui le regole di convalida integrate in Nette non sono sufficienti e dobbiamo convalidare i dati dell'utente a modo nostro. In Nette questo è molto semplice!
È possibile passare un qualsiasi callback come primo parametro ai metodi `addRule()` o `addCondition()`. La callback accetta l'elemento stesso come primo parametro e restituisce un valore booleano che indica se la validazione ha avuto successo. Quando si aggiunge una regola usando `addRule()`, si possono passare ulteriori argomenti, che vengono passati come secondo parametro.
L'insieme personalizzato di validatori può quindi essere creato come una classe con metodi statici:
```php
class MyValidators
{
// verifica se il valore è divisibile per l'argomento
public static function validateDivisibility(BaseControl $input, $arg): bool
{
return $input->getValue() % $arg === 0;
}
public static function validateEmailDomain(BaseControl $input, $domain)
{
// validatori aggiuntivi
}
}
```
L'utilizzo è quindi molto semplice:
```php
$form->addInteger('num')
->addRule(
[MyValidators::class, 'validateDivisibility'],
'The value must be a multiple of %d',
8,
);
```
Le regole di validazione personalizzate possono essere aggiunte anche a JavaScript. L'unico requisito è che la regola deve essere un metodo statico. Il suo nome per il validatore JavaScript viene creato concatenando il nome della classe senza backslash `\`, the underscore `_`, e il nome del metodo. Ad esempio, scrivere `App\MyValidators::validateDivisibility` come `AppMyValidators_validateDivisibility` e aggiungerlo all'oggetto `Nette.validators`:
```js
Nette.validators['AppMyValidators_validateDivisibility'] = (elem, args, val) => {
return val % args === 0;
};
```
Evento onValidate .[#toc-event-onvalidate]
==========================================
Dopo l'invio del modulo, la validazione viene eseguita controllando le singole regole aggiunte da `addRule()` e richiamando l'[evento |nette:glossary#Events] `onValidate`. Il suo gestore può essere usato per ulteriori convalide, in genere per verificare la corretta combinazione di valori in più elementi del modulo.
Se viene rilevato un errore, questo viene passato al modulo utilizzando il metodo `addError()`. Questo può essere richiamato sia su un elemento specifico che direttamente sul modulo.
```php
protected function createComponentSignInForm(): Form
{
$form = new Form;
// ...
$form->onValidate[] = [$this, 'validateSignInForm'];
return $form;
}
public function validateSignInForm(Form $form, \stdClass $data): void
{
if ($data->foo > 1 && $data->bar > 5) {
$form->addError('Questa combinazione non è possibile.');
}
}
```
Errori di elaborazione .[#toc-processing-errors]
================================================
In molti casi, si scopre un errore durante l'elaborazione di un modulo valido, ad esempio quando si scrive una nuova voce nel database e si incontra una chiave duplicata. In questo caso, si trasmette l'errore al modulo con il metodo `addError()`. Questo metodo può essere richiamato su un elemento specifico o direttamente sul modulo:
```php
try {
$data = $form->getValues();
$this->user->login($data->username, $data->password);
$this->redirect('Home:');
} catch (Nette\Security\AuthenticationException $e) {
if ($e->getCode() === Nette\Security\Authenticator::InvalidCredential) {
$form->addError('Invalid password.');
}
}
```
Se possibile, si consiglia di aggiungere l'errore direttamente all'elemento del form, poiché apparirà accanto a esso quando si utilizza il renderer predefinito.
```php
$form['date']->addError('Sorry, this date is already taken.');
```
È possibile chiamare ripetutamente `addError()` per passare più messaggi di errore a un form o a un elemento. Si ottengono con `getErrors()`.
Si noti che `$form->getErrors()` restituisce un riepilogo di tutti i messaggi di errore, anche quelli passati direttamente a singoli elementi, non solo direttamente al modulo. I messaggi di errore passati solo al modulo vengono recuperati con `$form->getOwnErrors()`.
Modifica dei valori di input .[#toc-modifying-input-values]
===========================================================
Utilizzando il metodo `addFilter()`, possiamo modificare il valore inserito dall'utente. In questo esempio, tollereremo e rimuoveremo gli spazi nel codice postale:
```php
$form->addText('zip', 'Codice postale:')
->addFilter(function ($value) {
return str_replace(' ', '', $value); // rimuove gli spazi dal codice postale
})
->addRule($form::Pattern, 'Il codice postale non è di cinque cifre', '\d{5}');
```
Il filtro è incluso tra le regole di validazione e le condizioni e quindi dipende dall'ordine dei metodi, cioè il filtro e la regola sono richiamati nello stesso ordine dei metodi `addFilter()` e `addRule()`.
Convalida JavaScript .[#toc-javascript-validation]
==================================================
Il linguaggio delle regole e delle condizioni di validazione è potente. Anche se tutti i costrutti funzionano sia lato server che lato client, in JavaScript. Le regole sono trasferite in attributi HTML `data-nette-rules` come JSON.
La validazione stessa è gestita da un altro script, che aggancia tutti gli eventi `submit` del modulo, itera su tutti gli input ed esegue le rispettive validazioni.
Questo script è `netteForms.js`, disponibile da diverse fonti:
È possibile incorporare lo script direttamente nella pagina HTML dal CDN:
```latte
<script src="https://unpkg.com/nette-forms@3"></script>
```
Oppure copiare localmente nella cartella pubblica del progetto (ad esempio da `vendor/nette/forms/src/assets/netteForms.min.js`):
```latte
<script src="/path/to/netteForms.min.js"></script>
```
Oppure installare tramite [npm |https://www.npmjs.com/package/nette-forms]:
```shell
npm install nette-forms
```
E poi caricare ed eseguire:
```js
import netteForms from 'nette-forms';
netteForms.initOnLoad();
```
In alternativa, è possibile caricarlo direttamente dalla cartella `vendor`:
```js
import netteForms from '../path/to/vendor/nette/forms/src/assets/netteForms.js';
netteForms.initOnLoad();
```
JavaScript dinamico .[#toc-dynamic-javascript]
==============================================
Volete mostrare i campi dell'indirizzo solo se l'utente sceglie di inviare la merce per posta? Nessun problema. La chiave è una coppia di metodi `addCondition()` e `toggle()`:
```php
$form->addCheckbox('send_it')
->addCondition($form::Equal, true)
->toggle('#address-container');
```
Questo codice dice che quando la condizione è soddisfatta, cioè quando la casella di controllo è selezionata, l'elemento HTML `#address-container` sarà visibile. E viceversa. Quindi, inseriamo gli elementi del modulo con l'indirizzo del destinatario in un contenitore con quell'ID e, quando si fa clic sulla casella di controllo, essi vengono nascosti o mostrati. Questo viene gestito dallo script `netteForms.js`.
Qualsiasi selettore può essere passato come argomento al metodo `toggle()`. Per ragioni storiche, una stringa alfanumerica senza altri caratteri speciali viene trattata come un ID di elemento, come se fosse preceduta dal simbolo `#` character. The second optional parameter allows us to reverse the behavior, i.e. if we used `toggle('#address-container', false)`, l'elemento verrebbe visualizzato solo se la casella di controllo fosse deselezionata.
L'implementazione predefinita di JavaScript modifica la proprietà `hidden` per gli elementi. Tuttavia, è possibile modificare facilmente il comportamento, ad esempio aggiungendo un'animazione. È sufficiente sovrascrivere il metodo `Nette.toggle` in JavaScript con una soluzione personalizzata:
```js
Nette.toggle = (selector, visible, srcElement, event) => {
document.querySelectorAll(selector).forEach((el) => {
// hide or show 'el' according to the value of 'visible'
});
};
```
Disabilitare la validazione .[#toc-disabling-validation]
========================================================
In alcuni casi, è necessario disabilitare la convalida. Se un pulsante di invio non deve eseguire la convalida dopo l'invio (per esempio il pulsante *Annulla* o *Anteprima*), si può disabilitare la convalida chiamando `$submit->setValidationScope([])`. È anche possibile convalidare parzialmente il modulo, specificando gli elementi da convalidare.
```php
$form->addText('name')
->setRequired();
$details = $form->addContainer('details');
$details->addInteger('age')
->setRequired('age');
$details->addInteger('age2')
->setRequired('age2');
$form->addSubmit('send1'); // Convalida l'intero modulo
$form->addSubmit('send2')
->setValidationScope([]); // Non convalida nulla
$form->addSubmit('send3')
->setValidationScope([$form['name']]); // Valida solo il campo 'name'.
$form->addSubmit('send4')
->setValidationScope([$form['details']['age']]); // Convalida solo il campo "età".
$form->addSubmit('send5')
->setValidationScope([$form['details']]); // Convalida il contenitore 'details'.
```
L'[evento onValidate |#Event onValidate] sul form è sempre invocato e non è influenzato dall'evento `setValidationScope`. `onValidate` sul contenitore è invocato solo quando questo contenitore è specificato per la validazione parziale.