Validarea formularelor
Controale obligatorii
Controalele sunt marcate ca fiind obligatorii cu ajutorul metodei setRequired()
, al cărei argument este textul mesajului de eroare care va fi afișat în cazul în care utilizatorul nu îl completează. Dacă
nu se furnizează niciun argument, se utilizează mesajul de eroare implicit.
$form->addText('name', 'Name:')
->setRequired('Please fill your name.');
Reguli
Adăugăm reguli de validare la controale cu ajutorul metodei addRule()
. Primul parametru este regula, al doilea
este mesajul de eroare, iar al treilea este argumentul regulii de validare.
$form->addPassword('password', 'Password:')
->addRule($form::MinLength, 'Password must be at least %d characters', 8);
Regula de validare este verificată numai dacă utilizatorul a completat elementul.
Nette vine cu un număr de reguli predefinite ale căror nume sunt constante din clasa Nette\Forms\Form
. Putem
aplica aceste reguli la toate elementele:
constantă | descriere | argumente |
---|---|---|
Required |
alias al setRequired() |
– |
Filled |
alias setRequired() |
– |
Blank |
nu trebuie să fie completat | – |
Equal |
valoarea este egală cu parametrul | mixed |
NotEqual |
value is not be equal to parameter | mixed |
IsIn |
valoarea este egală cu un element din matrice | – – – valoarea este egală cu un parametru array |
IsNotIn |
valoarea nu este egală cu nici un element din matrice | array |
Valid |
input passes validation (for conditions) | – |
Intrări de text
Pentru elementele addText()
, addPassword()
, addTextArea()
, addEmail()
,
addInteger()
, addFloat()
se pot aplica, de asemenea, unele dintre următoarele reguli:
MinLength |
lungime minimă a șirului de caractere | int |
MaxLength |
lungime maximă a șirului de caractere | int |
Length |
lungime în interval sau lungime exactă | pereche [int, int] sau int |
Email |
adresa de e-mail validă | – |
URL |
URL valid | – |
Pattern |
se potrivește cu un model regulat | string |
PatternInsensitive |
ca și Pattern , dar nu ține cont de majuscule și minuscule |
string |
Integer |
întreg | – |
Numeric |
pseudonimul lui Integer |
– |
Float |
întreg sau număr cu virgulă mobilă | – |
Min |
minimul valorii întregi | int|float |
Max |
maximum of the integer value | int|float |
Range |
valoare în intervalul de valori | pereche [int|float, int|float] |
Regulile Integer
, Numeric
și Float
convertesc automat valoarea în număr întreg (sau,
respectiv, flotant). În plus, regula URL
acceptă și o adresă fără o schemă (de exemplu,
nette.org
) și completează schema (https://nette.org
). Expresiile din Pattern
și
PatternInsensitive
trebuie să fie valabile pentru întreaga valoare, adică ca și cum ar fi înfășurată în
caracterele ^
and $
.
Număr de articole
Pentru elementele addMultiUpload()
, addCheckboxList()
, addMultiSelect()
puteți utiliza,
de asemenea, următoarele reguli pentru a limita numărul de elemente selectate sau de fișiere încărcate:
MinLength |
număr minim | int |
MaxLength |
număr maxim | int |
Length |
număr în interval sau număr exact | perechi [int, int] sau int |
Încărcare fișier
Pentru controalele addUpload()
, addMultiUpload()
se pot utiliza, de asemenea, următoarele
reguli:
MaxFileSize |
dimensiunea maximă a fișierului în bytes | int |
MimeType |
tip MIME, acceptă wildcards ('video/*' ) |
string|string[] |
Image |
fișierul încărcat este JPEG, PNG, GIF, WebP | – |
Pattern |
numele fișierului se potrivește cu o expresie regulată | string |
PatternInsensitive |
ca Pattern , dar nu ține cont de majuscule și minuscule |
string |
MimeType
și Image
necesită extensia PHP fileinfo
. Dacă un fișier sau o imagine este
de tipul cerut este detectat prin semnătura sa. Integritatea întregului fișier nu este verificată. Puteți afla dacă
o imagine nu este coruptă, de exemplu, încercând să o încărcați.
Mesaje de eroare
Toate regulile predefinite, cu excepția Pattern
și PatternInsensitive
, au un mesaj de eroare
implicit, astfel încât acestea pot fi omise. Cu toate acestea, dacă treceți și formulați toate mesajele personalizate, veți
face formularul mai ușor de utilizat.
Puteți schimba mesajele implicite în configuration, modificând
textele din matricea Nette\Forms\Validator::$messages
sau utilizând translator.
În textul mesajelor de eroare pot fi utilizate următoarele caractere wildcards:
%d |
înlocuiește treptat regulile de după argumente |
%n$d |
înlocuiește cu al n-lea argument al regulii |
%label |
înlocuiește cu eticheta câmpului (fără două puncte) |
%name |
înlocuiește cu numele câmpului (de exemplu, name ) |
%value |
înlocuiește cu valoarea introdusă de utilizator |
$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]);
Condiții
Pe lângă regulile de validare, pot fi stabilite și condiții. Acestea se stabilesc la fel ca regulile, însă folosim
addRule()
în loc de addCondition()
și, bineînțeles, lăsăm fără un mesaj de eroare (condiția
doar întreabă):
$form->addPassword('password', 'Password:')
// dacă parola nu are mai mult de 8 caractere ...
->addCondition($form::MaxLength, 8)
// ... atunci trebuie să conțină un număr
->addRule($form::Pattern, 'Must contain number', '.*[0-9].*');
Condiția poate fi legată de un alt element decât cel curent folosind addConditionOn()
. Primul parametru este
o referință la câmp. În cazul următor, e-mailul va fi necesar numai dacă caseta de selectare este bifată (adică dacă
valoarea sa este true
):
$form->addCheckbox('newsletters', 'send me newsletters');
$form->addEmail('email', 'Email:')
// dacă caseta de selectare este bifată ...
->addConditionOn($form['newsletters'], $form::Equal, true)
// ... necesită e-mail
->setRequired('Fill your email address');
Condițiile pot fi grupate în structuri complexe cu ajutorul metodelor elseCondition()
și
endCondition()
.
$form->addText(/* ... */)
->addCondition(/* ... */) // dacă este îndeplinită prima condiție
->addConditionOn(/* ... */) // și a doua condiție și la un alt element
->addRule(/* ... */) // necesită această regulă
->elseCondition() // dacă a doua condiție nu este îndeplinită
->addRule(/* ... */) // necesită aceste reguli
->addRule(/* ... */)
->endCondition() // se revine la prima condiție
->addRule(/* ... */);
În Nette, este foarte ușor să reacționați la îndeplinirea sau nu a unei condiții pe partea de JavaScript folosind metoda
toggle()
, consultați Dynamic JavaScript.
Trimitere la un alt element
Ca argument pentru o regulă sau o condiție, puteți trece și un alt element de formular. Regula va utiliza apoi valoarea
introdusă ulterior de utilizator în browser. Acest lucru poate fi utilizat, de exemplu, pentru a valida dinamic faptul că
elementul password
conține același șir de caractere ca elementul password_confirm
:
$form->addPassword('password', 'Password');
$form->addPassword('password_confirm', 'Confirm Password')
->addRule($form::Equal, 'The passwords do not match', $form['password']);
Reguli și condiții personalizate
Uneori, ne aflăm într-o situație în care regulile de validare încorporate în Nette nu sunt suficiente și trebuie să validăm datele de la utilizator în felul nostru propriu. În Nette acest lucru este foarte ușor!
Puteți trece orice callback ca prim parametru al metodelor addRule()
sau addCondition()
. Callback-ul
acceptă elementul însuși ca prim parametru și returnează o valoare booleană care indică dacă validarea a avut succes sau
nu. Atunci când se adaugă o regulă folosind addRule()
, se pot trece argumente suplimentare, iar acestea sunt apoi
trecute ca al doilea parametru.
Setul personalizat de validatoare poate fi astfel creat ca o clasă cu metode statice:
class MyValidators
{
// testează dacă valoarea este divizibilă cu argumentul
public static function validateDivisibility(BaseControl $input, $arg): bool
{
return $input->getValue() % $arg === 0;
}
public static function validateEmailDomain(BaseControl $input, $domain)
{
// validatori suplimentari
}
}
Utilizarea este apoi foarte simplă:
$form->addInteger('num')
->addRule(
[MyValidators::class, 'validateDivisibility'],
'The value must be a multiple of %d',
8,
);
Regulile de validare personalizate pot fi, de asemenea, adăugate la JavaScript. Singura cerință este ca regula să fie
o metodă statică. Numele acesteia pentru validatorul JavaScript este creat prin concatenarea numelui clasei fără
backslash-uri \
, the underscore _
, și a numelui metodei. De exemplu, scrieți
App\MyValidators::validateDivisibility
ca AppMyValidators_validateDivisibility
și adăugați-o la
obiectul Nette.validators
:
Nette.validators['AppMyValidators_validateDivisibility'] = (elem, args, val) => {
return val % args === 0;
};
Eveniment onValidate
După trimiterea formularului, validarea este efectuată prin verificarea regulilor individuale adăugate de
addRule()
și apoi prin apelarea evenimentului
onValidate
. Gestionarul acestuia poate fi utilizat pentru validare suplimentară, de obicei pentru a verifica
combinația corectă de valori în mai multe elemente ale formularului.
În cazul în care se detectează o eroare, aceasta este transmisă formularului cu ajutorul metodei addError()
.
Aceasta poate fi apelată fie pe un anumit element, fie direct pe formular.
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('This combination is not possible.');
}
}
Erori de procesare
În multe cazuri, descoperim o eroare atunci când procesăm un formular valid, de exemplu, atunci când scriem o nouă
intrare în baza de date și întâlnim o cheie duplicată. În acest caz, transmitem eroarea înapoi la formular folosind metoda
addError()
. Aceasta poate fi apelată fie pe un element specific, fie direct pe formular:
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.');
}
}
Dacă este posibil, vă recomandăm să adăugați eroarea direct la elementul de formular, deoarece va apărea lângă acesta atunci când se utilizează randarea implicită.
$form['date']->addError('Sorry, this date is already taken.');
Puteți apela addError()
în mod repetat pentru a transmite mai multe mesaje de eroare unui formular sau element.
Le obțineți cu getErrors()
.
Rețineți că $form->getErrors()
returnează un rezumat al tuturor mesajelor de eroare, chiar și al celor
transmise direct către elemente individuale, nu doar direct către formular. Mesajele de eroare transmise doar la formular sunt
recuperate prin $form->getOwnErrors()
.
Modificarea valorilor de intrare
Utilizând metoda addFilter()
, putem modifica valoarea introdusă de utilizator. În acest exemplu, vom tolera și
elimina spațiile din codul poștal:
$form->addText('zip', 'Postcode:')
->addFilter(function ($value) {
return str_replace(' ', '', $value); // eliminați spațiile din codul poștal
})
->addRule($form::Pattern, 'The postal code is not five digits', '\d{5}');
Filtrul este inclus între regulile și condițiile de validare și, prin urmare, depinde de ordinea metodelor, adică filtrul
și regula sunt apelate în aceeași ordine ca și ordinea metodelor addFilter()
și addRule()
.
Validarea JavaScript
Limbajul regulilor și condițiilor de validare este puternic. Chiar dacă toate construcțiile funcționează atât pe partea
serverului, cât și pe partea clientului, în JavaScript. Regulile sunt transferate în atributele HTML
data-nette-rules
ca JSON. Validarea propriu-zisă este gestionată de un alt script, care agață toate evenimentele
submit
ale formularului, itera peste toate intrările și execută validările respective.
Acest script este netteForms.js
, care este disponibil din mai multe surse posibile:
Puteți încorpora scriptul direct în pagina HTML din CDN:
<script src="https://unpkg.com/nette-forms@3"></script>
Sau copiați local în folderul public al proiectului (de exemplu, de la
vendor/nette/forms/src/assets/netteForms.min.js
):
<script src="/path/to/netteForms.min.js"></script>
Sau instalați prin npm:
npm install nette-forms
Și apoi încărcați și rulați:
import netteForms from 'nette-forms';
netteForms.initOnLoad();
Alternativ, îl puteți încărca direct din folderul vendor
:
import netteForms from '../path/to/vendor/nette/forms/src/assets/netteForms.js';
netteForms.initOnLoad();
JavaScript dinamic
Doriți să afișați câmpurile de adresă doar dacă utilizatorul alege să trimită bunurile prin poștă? Nu este nicio
problemă. Cheia este o pereche de metode addCondition()
& toggle()
:
$form->addCheckbox('send_it')
->addCondition($form::Equal, true)
->toggle('#address-container');
Acest cod spune că atunci când condiția este îndeplinită, adică atunci când caseta de selectare este bifată, elementul
HTML #address-container
va fi vizibil. Și viceversa. Așadar, plasăm elementele de formular cu adresa
destinatarului într-un container cu acest ID, iar atunci când se face clic pe caseta de selectare, acestea sunt ascunse sau
afișate. Acest lucru este gestionat de scriptul netteForms.js
.
Orice selector poate fi trecut ca argument pentru metoda toggle()
. Din motive istorice, un șir de caractere
alfanumerice fără alte caractere speciale este tratat ca un ID de element, la fel ca și cum ar fi precedat de #
character. The second optional parameter allows us to reverse the behavior, i.e. if we used
toggle('#address-container', false)
, elementul ar fi afișat numai dacă caseta de selectare ar fi debifată.
Implementarea implicită a JavaScript modifică proprietatea hidden
pentru elemente. Cu toate acestea, putem
schimba cu ușurință comportamentul, de exemplu prin adăugarea unei animații. Trebuie doar să suprascrieți metoda
Nette.toggle
în JavaScript cu o soluție personalizată:
Nette.toggle = (selector, visible, srcElement, event) => {
document.querySelectorAll(selector).forEach((el) => {
// hide or show 'el' according to the value of 'visible'
});
};
Dezactivarea validării
În anumite cazuri, este necesar să dezactivați validarea. Dacă un buton de trimitere nu trebuie să execute validarea după
trimitere (de exemplu, butonul Cancel sau Preview), puteți dezactiva validarea prin apelarea
$submit->setValidationScope([])
. De asemenea, puteți valida formularul parțial, specificând elementele care
trebuie validate.
$form->addText('name')
->setRequired();
$details = $form->addContainer('details');
$details->addInteger('age')
->setRequired('age');
$details->addInteger('age2')
->setRequired('age2');
$form->addSubmit('send1'); // Validează întregul formular
$form->addSubmit('send2')
->setValidationScope([]); // Nu validează nimic
$form->addSubmit('send3')
->setValidationScope([$form['name']]); // Validează doar câmpul "name" (nume)
$form->addSubmit('send4')
->setValidationScope([$form['details']['age']]); // Validează doar câmpul "vârstă".
$form->addSubmit('send5')
->setValidationScope([$form['details']]); // Validează recipientul "details" (detalii)
Evenimentul onValidate de pe formular este întotdeauna invocat și nu este afectat de
setValidationScope
. Evenimentul onValidate
de pe container este invocat numai atunci când acest
container este specificat pentru validare parțială.