Nette Documentation Preview

syntax
Validarea formularelor
**********************


Controale obligatorii .[#toc-required-controls]
===============================================

Controalele sunt marcate ca fiind obligatorii cu ajutorul metodei `setRequired()`, al cărei argument este textul [mesajului de eroare |#Error Messages] 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.

```php
$form->addText('name', 'Name:')
	->setRequired('Please fill your name.');
```


Reguli .[#toc-rules]
====================

Adăugăm reguli de validare la controale cu ajutorul metodei `addRule()`. Primul parametru este regula, al doilea este [mesajul de eroare |#Error Messages], iar al treilea este argumentul regulii de validare.

```php
$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 |#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 .[#toc-number-of-items]
-----------------------------------------

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 |http:request#toImage].


Mesaje de eroare .[#toc-error-messages]
=======================================

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 [forms:configuration], modificând textele din matricea `Nette\Forms\Validator::$messages` sau utilizând [translator |rendering#translating].

Î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

```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]);
```


Condiții .[#toc-conditions]
===========================

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ă):

```php
$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`):

```php
$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()`.

```php
$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 |#Dynamic JavaScript].


Referințe între controale .[#toc-references-between-controls]
=============================================================

Argumentul regulii sau al condiției poate fi o referință la un alt element. De exemplu, puteți valida în mod dinamic faptul că `text` are atâtea caractere cât este valoarea câmpului `length`:

```php
$form->addInteger('length');
$form->addText('text')
	->addRule($form::Length, null, $form['length']);
```


Reguli și condiții personalizate .[#toc-custom-rules-and-conditions]
====================================================================

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:

```php
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ă:

```php
$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`:

```js
Nette.validators['AppMyValidators_validateDivisibility'] = (elem, args, val) => {
	return val % args === 0;
};
```


Eveniment onValidate .[#toc-event-onvalidate]
=============================================

După trimiterea formularului, validarea este efectuată prin verificarea regulilor individuale adăugate de `addRule()` și apoi prin apelarea [evenimentului |nette:glossary#Events] `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.

```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('This combination is not possible.');
	}
}
```


Erori de procesare .[#toc-processing-errors]
============================================

Î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:

```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.');
	}
}
```

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ă.

```php
$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 .[#toc-modifying-input-values]
===============================================================

Utilizând metoda `addFilter()`, putem modifica valoarea introdusă de utilizator. În acest exemplu, vom tolera și elimina spațiile din codul poștal:

```php
$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 .[#toc-javascript-validation]
==================================================

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:

```latte
<script src="https://unpkg.com/nette-forms@3/src/assets/netteForms.js"></script>
```

Sau copiați local în folderul public al proiectului (de exemplu, de la `vendor/nette/forms/src/assets/netteForms.min.js`):

```latte
<script src="/path/to/netteForms.min.js"></script>
```

Sau instalați prin [npm |https://www.npmjs.com/package/nette-forms]:

```shell
npm install nette-forms
```

Și apoi încărcați și rulați:

```js
import netteForms from 'nette-forms';
netteForms.initOnLoad();
```

Alternativ, îl puteți încărca direct din folderul `vendor`:

```js
import netteForms from '../path/to/vendor/nette/forms/src/assets/netteForms.js';
netteForms.initOnLoad();
```


JavaScript dinamic .[#toc-dynamic-javascript]
=============================================

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()`:

```php
$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ă:

```js
Nette.toggle = (selector, visible, srcElement, event) => {
	document.querySelectorAll(selector).forEach((el) => {
		// hide or show 'el' according to the value of 'visible'
	});
};
```


Dezactivarea validării .[#toc-disabling-validation]
===================================================

Î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.

```php
$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 |#Event 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ă.

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.

Referințe între controale

Argumentul regulii sau al condiției poate fi o referință la un alt element. De exemplu, puteți valida în mod dinamic faptul că text are atâtea caractere cât este valoarea câmpului length:

$form->addInteger('length');
$form->addText('text')
	->addRule($form::Length, null, $form['length']);

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/src/assets/netteForms.js"></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ă.