Convalida dei moduli
Controlli richiesti
I controlli vengono contrassegnati come obbligatori con il metodo setRequired()
, il cui argomento è il testo del
messaggio di errore che verrà visualizzato se l'utente non lo compila. Se non viene fornito
alcun argomento, viene utilizzato il messaggio di errore predefinito.
$form->addText('name', 'Name:')
->setRequired('Please fill your name.');
Regole
Con il metodo addRule()
si aggiungono regole di convalida ai controlli. Il primo parametro è la regola, il
secondo è il messaggio di errore e il terzo è l'argomento della regola di validazione.
$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) | – |
Ingressi di testo
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
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.
Messaggi di errore
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,
modificando i testi dell'array Nette\Forms\Validator::$messages
o utilizzando il traduttore.
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 |
$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
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):
$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
):
$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()
.
$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.
Riferimento a un altro elemento
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
:
$form->addPassword('password', 'Password');
$form->addPassword('password_confirm', 'Confirm Password')
->addRule($form::Equal, 'The passwords do not match', $form['password']);
Regole e condizioni personalizzate
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:
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:
$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
:
Nette.validators['AppMyValidators_validateDivisibility'] = (elem, args, val) => {
return val % args === 0;
};
Evento onValidate
Dopo l'invio del modulo, la validazione viene eseguita controllando le singole regole aggiunte da addRule()
e
richiamando l'evento 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.
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
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:
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.
$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
Utilizzando il metodo addFilter()
, possiamo modificare il valore inserito dall'utente. In questo esempio,
tollereremo e rimuoveremo gli spazi nel codice postale:
$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
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:
<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
):
<script src="/path/to/netteForms.min.js"></script>
Oppure installare tramite npm:
npm install nette-forms
E poi caricare ed eseguire:
import netteForms from 'nette-forms';
netteForms.initOnLoad();
In alternativa, è possibile caricarlo direttamente dalla cartella vendor
:
import netteForms from '../path/to/vendor/nette/forms/src/assets/netteForms.js';
netteForms.initOnLoad();
JavaScript dinamico
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()
:
$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:
Nette.toggle = (selector, visible, srcElement, event) => {
document.querySelectorAll(selector).forEach((el) => {
// hide or show 'el' according to the value of 'visible'
});
};
Disabilitare la validazione
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.
$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 sul form è sempre invocato e non è influenzato dall'evento
setValidationScope
. onValidate
sul contenitore è invocato solo quando questo contenitore è specificato
per la validazione parziale.