Nette Documentation Preview

syntax
Nyomtatványok érvényesítés
**************************


Kötelező vezérlők .[#toc-required-controls]
===========================================

A vezérlőelemeket a `setRequired()` metódussal jelöljük meg kötelezőnek, amelynek argumentuma a [hibaüzenet |#Error Messages] szövege, amely akkor jelenik meg, ha a felhasználó nem tölti ki. Ha nem adunk meg argumentumot, akkor az alapértelmezett hibaüzenetet használjuk.

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


Szabályok .[#toc-rules]
=======================

A `addRule()` módszerrel adunk hozzá érvényesítési szabályokat a vezérlőkhöz. Az első paraméter a szabály, a második a [hibaüzenet |#Error Messages], a harmadik pedig az érvényesítési szabály argumentuma.

```php
$form->addPassword('password', 'Password:')
	->addRule($form::MinLength, 'Password must be at least %d characters', 8);
```

**A hitelesítési szabályok csak akkor kerülnek ellenőrzésre, ha a felhasználó kitöltötte az elemet.**

A Nette számos előre definiált szabályt tartalmaz, amelyek neve a `Nette\Forms\Form` osztály konstanciái. Ezeket a szabályokat minden elemre alkalmazhatjuk:

| konstans | leírás | érvek
|-------
| `Required` | `setRequired()` álneve | - -
| `Filled` | a `setRequired()` álneve | -
| `Blank` | nem szabad kitölteni | -
| `Equal` | érték egyenlő a paraméterrel | `mixed`
| `NotEqual` | érték nem egyenlő a paraméterrel | `mixed`
| `IsIn` | érték egyenlő a tömb valamelyik elemével | `array`
| `IsNotIn` | érték nem egyenlő a tömb egyetlen elemével sem | `array`
| `Valid` | a bemenet átmegy az érvényesítésen ( [feltételek |#conditions] esetén) | -


Szöveges bemenetek
------------------

A `addText()`, `addPassword()`, `addTextArea()`, `addEmail()`, `addInteger()`, `addFloat()` elemekre a következő szabályok közül néhányat is lehet alkalmazni:

| `MinLength` | minimális karakterlánc-hossz | `int`
| `MaxLength` | maximális karakterlánc-hossz | `int`
| `Length` | hossz a tartományban vagy pontos hossz | pár `[int, int]` vagy `int`
| `Email` | érvényes e-mail cím | -
| `URL` | érvényes URL | -
| `Pattern` | megfelel a szabályos mintának | `string`
| `PatternInsensitive` | mint a `Pattern`, de a nagy- és kisbetűket figyelmen kívül hagyja | `string`
| `Integer` | egész szám | -
| `Numeric` | `Integer` álneve | -
| `Float` | egész vagy lebegőpontos szám | -
| `Min` | az egész szám értékének minimuma | `int\|float`
| `Max` | az egész szám értékének maximuma | `int\|float`
| `Range` | érték a tartományban | pár `[int\|float, int\|float]`

A `Integer`, `Numeric` és `Float` szabályok automatikusan egész számra (illetve lebegőszámra) konvertálják az értéket. Továbbá a `URL` szabály elfogad egy séma nélküli címet is (pl. `nette.org`), és kiegészíti a sémát (`https://nette.org`).
A `Pattern` és a `PatternInsensitive` kifejezéseknek a teljes értékre érvényesnek kell lenniük, azaz mintha a `^` and `$` karakterekbe lenne csomagolva.


Tételek száma .[#toc-number-of-items]
-------------------------------------

A `addMultiUpload()`, `addCheckboxList()`, `addMultiSelect()` elemek esetében a következő szabályokkal is korlátozhatja a kiválasztott elemek vagy feltöltött fájlok számát:

| `MinLength` | minimális szám | `int`
| `MaxLength` | maximális szám | `int`
| `Length` | szám tartományon belül vagy pontos szám | párok `[int, int]` vagy `int`


Fájl feltöltés
--------------

A `addUpload()`, `addMultiUpload()` vezérlőkre a következő szabályok is alkalmazhatók:

| `MaxFileSize` | maximális fájlméret bájtban | `int`
| `MimeType` | MIME-típus, elfogadja a helyettesítő karaktereket (`'video/*'`) | `string\|string[]`
| `Image` | a feltöltött fájl JPEG, PNG, GIF, WebP | -
| `Pattern` | a fájl neve megfelel a reguláris kifejezésnek | `string`
| `PatternInsensitive` | mint a `Pattern`, de a nagy- és kisbetűket nem érzékeli | `string`

A `MimeType` és a `Image` a `fileinfo` PHP kiterjesztést igényli. Az, hogy egy fájl vagy kép a kívánt típusba tartozik-e, az aláírás alapján állapítható meg. A teljes fájl sértetlenségét nem ellenőrzi a rendszer. Azt, hogy egy kép nem sérült-e, például úgy lehet megállapítani, ha megpróbáljuk [betölteni |http:request#toImage].


Hibaüzenetek .[#toc-error-messages]
===================================

A `Pattern` és a `PatternInsensitive` kivételével minden előre definiált szabály rendelkezik alapértelmezett hibaüzenettel, így ezek elhagyhatók. Az összes testreszabott üzenet átadásával és megfogalmazásával azonban felhasználóbarátabbá teszi az űrlapot.

Az alapértelmezett üzeneteket a [forms:configuration-ban |forms:configuration], a `Nette\Forms\Validator::$messages` tömbben lévő szövegek módosításával vagy a [translator |rendering#translating] használatával módosíthatja.

A hibaüzenetek szövegében a következő helyettesítő karakterek használhatók:

| `%d` | fokozatosan helyettesíti a szabályokat az argumentumok után.
| `%n$d` | az n-edik szabály argumentumával helyettesíti.
| `%label` | a mező címkéjével helyettesíti (kettőspont nélkül)
| `%name` | a mező nevével helyettesíti (pl. `name`).
| `%value` | a felhasználó által megadott értékkel helyettesíti.

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


Feltételek .[#toc-conditions]
=============================

Az érvényesítési szabályok mellett feltételek is beállíthatók. Ezek beállítása hasonlóan történik, mint a szabályoké, azonban a `addCondition()` helyett a `addRule()` címet használjuk, és természetesen hibaüzenet nélkül hagyjuk (a feltétel csak kérdez):

```php
$form->addPassword('password', 'Jelszó:')
	// ha a jelszó nem hosszabb 8 karakternél ...
	->addCondition($form::MaxLength, 8)
		// ... akkor egy számot kell tartalmaznia.
		->addRule($form::Pattern, 'Számot kell tartalmaznia', '.*[0-9].*');
```

A feltétel a `addConditionOn()` segítségével az aktuális elemtől eltérő elemhez is kapcsolható. Az első paraméter a mezőre való hivatkozás. A következő esetben az e-mail csak akkor lesz kötelező, ha a jelölőnégyzet be van jelölve (azaz az értéke `true`):

```php
$form->addCheckbox('newsletters', 'send me newsletters');

$form->addEmail('email', 'Email:')
	// ha a jelölőnégyzet be van jelölve ...
	->addConditionOn($form['newsletters'], $form::Equal, true)
		// ... megköveteli az email
		->setRequired('Adja meg az e-mail címét');
```

A feltételek a `elseCondition()` és a `endCondition()` metódusokkal összetett struktúrákba csoportosíthatók.

```php
$form->addText(/* ... */)
	->addCondition(/* ... */) // ha az első feltétel teljesül.
		->addConditionOn(/* ... */) // és a második feltétel egy másik elemre is.
			->addRule(/* ... */) // megköveteli ezt a szabályt
		->elseCondition() // ha a második feltétel nem teljesül
			->addRule(/* ... */) // szükség van ezekre a szabályokra.
			->addRule(/* ... */)
		->endCondition() // visszatérünk az első feltételhez
		->addRule(/* ... */);
```

A Nette-ben nagyon egyszerűen reagálhatunk egy feltétel teljesülésére vagy nem teljesülésére a JavaScript oldalán a `toggle()` metódus segítségével, lásd [Dynamic JavaScript |#Dynamic JavaScript].


Hivatkozások a vezérlők között .[#toc-references-between-controls]
==================================================================

A szabály vagy feltétel argumentum lehet hivatkozás egy másik elemre. Például dinamikusan érvényesítheti, hogy a `text` annyi karaktert tartalmazzon, ahány karakter a `length` mező értéke:

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


Egyéni szabályok és feltételek .[#toc-custom-rules-and-conditions]
==================================================================

Néha olyan helyzetbe kerülünk, amikor a Nette beépített érvényesítési szabályai nem elegendőek, és a felhasználó adatait saját módon kell érvényesítenünk. A Nette-ben ez nagyon egyszerű!

A `addRule()` vagy a `addCondition()` metódusok első paramétereként bármilyen visszahívást átadhatunk. A callback első paraméterként magát az elemet fogadja el, és egy bóluszi értéket ad vissza, amely jelzi, hogy az érvényesítés sikeres volt-e. Szabály hozzáadásakor a `addRule()` segítségével további argumentumok adhatók át, amelyek második paraméterként kerülnek átadásra.

Az egyéni érvényesítőkészlet tehát statikus metódusokkal rendelkező osztályként hozható létre:

```php
class MyValidators
{
	// teszteli, hogy az érték osztható-e az argumentummal.
	public static function validateDivisibility(BaseControl $input, $arg): bool
	{
		return $input->getValue() % $arg === 0;
	}

	public static function validateEmailDomain(BaseControl $input, $domain)
	{
		// további validátorok
	}
}
```

A használat nagyon egyszerű:

```php
$form->addInteger('num')
	->addRule(
		[MyValidators::class, 'validateDivisibility'],
		'The value must be a multiple of %d',
		8,
	);
```

Egyéni érvényesítési szabályokat is hozzá lehet adni a JavaScripthez. Az egyetlen követelmény, hogy a szabály statikus metódus legyen. Nevét a JavaScript-érvényesítő számára az osztály neve (backslashes nélkül) `\`, the underscore `_`, és a metódus neve egymás mellé fűzésével hozzuk létre. Például írjuk a `App\MyValidators::validateDivisibility` -t `AppMyValidators_validateDivisibility` néven, és adjuk hozzá a `Nette.validators` objektumhoz:

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


Esemény onValidate .[#toc-event-onvalidate]
===========================================

Az űrlap elküldése után az érvényesítés a `addRule()` által hozzáadott egyedi szabályok ellenőrzésével, majd a `onValidate`[esemény |nette:glossary#Events] meghívásával történik. Kezelője további érvényesítésre használható, jellemzően több űrlapelem értékének helyes kombinációjának ellenőrzésére.

Ha hibát észlel, azt a `addError()` metódus segítségével továbbítja az űrlapnak. Ezt vagy egy adott elemen, vagy közvetlenül az űrlapon lehet meghívni.

```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('Ez a kombináció nem lehetséges.');
	}
}
```


Hibák feldolgozása .[#toc-processing-errors]
============================================

Sok esetben egy érvényes űrlap feldolgozása közben fedezünk fel hibát, például amikor új bejegyzést írunk az adatbázisba, és egy duplikált kulcsot találunk. Ebben az esetben a `addError()` metódus segítségével adjuk vissza a hibát az űrlapnak. Ezt vagy egy adott elemen, vagy közvetlenül az űrlapon hívhatjuk meg:

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

Ha lehetséges, javasoljuk, hogy a hibát közvetlenül az űrlap elemhez adjuk hozzá, mivel az alapértelmezett renderelő használata esetén a hiba mellette fog megjelenni.

```php
$form['date']->addError('Sorry, this date is already taken.');
```

A `addError()` többször is meghívható, hogy több hibaüzenetet adjon át egy űrlapnak vagy elemnek. Ezeket a `getErrors()` segítségével kapja meg.

Vegye figyelembe, hogy a `$form->getErrors()` az összes hibaüzenet összefoglalóját adja vissza, még a közvetlenül az egyes elemeknek átadottakat is, nem csak közvetlenül az űrlapnak. A csak az űrlapnak átadott hibaüzeneteket a `$form->getOwnErrors()` segítségével kapjuk meg.


A beviteli értékek módosítása .[#toc-modifying-input-values]
============================================================

A `addFilter()` módszerrel módosíthatjuk a felhasználó által megadott értéket. Ebben a példában megtűrjük és eltávolítjuk a szóközöket az irányítószámban:

```php
$form->addText('zip', 'Irányítószám:')
	->addFilter(function ($value) {
		return str_replace(' ', '', $value); // eltávolítjuk a szóközöket az irányítószámból.
	})
	->addRule($form::Pattern, 'Az irányítószám nem ötjegyű', '\d{5}');
```

A szűrő az érvényesítési szabályok és feltételek között szerepel, ezért függ a módszerek sorrendjétől, azaz a szűrő és a szabály meghívása ugyanabban a sorrendben történik, mint a `addFilter()` és a `addRule()` módszerek sorrendje.


JavaScript érvényesítés .[#toc-javascript-validation]
=====================================================

Az érvényesítési szabályok és feltételek nyelve nagy teljesítményű. Annak ellenére, hogy minden konstrukció szerver- és kliensoldalon egyaránt működik, JavaScriptben. A szabályok átadása HTML-attribútumokban történik `data-nette-rules` JSON-ként.
Magát az érvényesítést egy másik szkript kezeli, amely az űrlap összes `submit` eseményét megakasztja, iterálja az összes bemenetet és lefuttatja a megfelelő érvényesítéseket.

Ez a szkript a `netteForms.js`, amely több lehetséges forrásból is elérhető:

A szkriptet közvetlenül a CDN-ből származó HTML-oldalba ágyazhatja be:

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

Vagy másolja be helyileg a projekt nyilvános mappájába (pl. a `vendor/nette/forms/src/assets/netteForms.min.js`):

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

Vagy telepítse az [npm |https://www.npmjs.com/package/nette-forms] segítségével:

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

Aztán töltsd be és futtasd:

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

Alternatívaként közvetlenül a `vendor` mappából is betöltheti:

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


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

Csak akkor szeretné megjeleníteni a cím mezőt, ha a felhasználó úgy dönt, hogy postai úton küldi el az árut? Nem probléma. A kulcs a `addCondition()` & `toggle()` metóduspár:

```php
$form->addCheckbox('send_it')
	->addCondition($form::Equal, true)
		->toggle('#address-container');
```

Ez a kód azt mondja, hogy ha a feltétel teljesül, vagyis ha a jelölőnégyzet be van jelölve, akkor a `#address-container` HTML-elem láthatóvá válik. És fordítva. Tehát a címzett címét tartalmazó űrlapelemeket egy ilyen azonosítóval rendelkező konténerbe helyezzük, és amikor a jelölőnégyzetre kattintunk, elrejtjük vagy megjelenítjük őket. Ezt a `netteForms.js` szkript kezeli.

A `toggle()` metódusnak argumentumként bármilyen szelektor átadható. Történelmi okokból a más speciális karaktereket nem tartalmazó alfanumerikus karakterláncot elemazonosítóként kezeljük, ugyanúgy, mintha a `#` character. The second optional parameter allows us to reverse the behavior, i.e. if we used `toggle('#address-container', false)` lenne előtte, az elem csak akkor jelenne meg, ha a jelölőnégyzet nincs bejelölve.

Az alapértelmezett JavaScript implementáció megváltoztatja az elemek `hidden` tulajdonságát. A viselkedést azonban könnyen megváltoztathatjuk, például egy animáció hozzáadásával. Csak írjuk felül a `Nette.toggle` metódust JavaScriptben egy egyéni megoldással:

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


Az érvényesítés letiltása .[#toc-disabling-validation]
======================================================

Bizonyos esetekben le kell tiltani az érvényesítést. Ha egy beküldőgombnak nem kellene érvényesítést futtatnia a beküldés után (például *Mondás* vagy *Közlemény* gomb), akkor az érvényesítést a `$submit->setValidationScope([])` meghívásával tilthatja le. Az űrlapot részlegesen is érvényesítheti az érvényesítendő elemek megadásával.

```php
$form->addText('name')
	->setRequired();

$details = $form->addContainer('details');
$details->addInteger('age')
	->setRequired('age');
$details->addInteger('age2')
	->setRequired('age2');

$form->addSubmit('send1'); // Az egész űrlap hitelesítése
$form->addSubmit('send2')
	->setValidationScope([]); // Nem érvényesít semmit.
$form->addSubmit('send3')
	->setValidationScope([$form['name']]); // Csak a 'name' mezőt érvényesíti.
$form->addSubmit('send4')
	->setValidationScope([$form['details']['age']]); // Csak az 'age' mezőt érvényesíti.
$form->addSubmit('send5')
	->setValidationScope([$form['details']]); // Validálja a 'details' konténert.
```

[Az onValidate esemény |#Event onValidate] az űrlapon mindig meghívásra kerül, és nem befolyásolja a `setValidationScope`. `onValidate` esemény a konténeren csak akkor hívódik meg, ha ez a konténer részleges érvényesítésre van megadva.

Nyomtatványok érvényesítés

Kötelező vezérlők

A vezérlőelemeket a setRequired() metódussal jelöljük meg kötelezőnek, amelynek argumentuma a hibaüzenet szövege, amely akkor jelenik meg, ha a felhasználó nem tölti ki. Ha nem adunk meg argumentumot, akkor az alapértelmezett hibaüzenetet használjuk.

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

Szabályok

A addRule() módszerrel adunk hozzá érvényesítési szabályokat a vezérlőkhöz. Az első paraméter a szabály, a második a hibaüzenet, a harmadik pedig az érvényesítési szabály argumentuma.

$form->addPassword('password', 'Password:')
	->addRule($form::MinLength, 'Password must be at least %d characters', 8);

A hitelesítési szabályok csak akkor kerülnek ellenőrzésre, ha a felhasználó kitöltötte az elemet.

A Nette számos előre definiált szabályt tartalmaz, amelyek neve a Nette\Forms\Form osztály konstanciái. Ezeket a szabályokat minden elemre alkalmazhatjuk:

konstans leírás érvek
Required setRequired() álneve – –
Filled a setRequired() álneve
Blank nem szabad kitölteni
Equal érték egyenlő a paraméterrel mixed
NotEqual érték nem egyenlő a paraméterrel mixed
IsIn érték egyenlő a tömb valamelyik elemével array
IsNotIn érték nem egyenlő a tömb egyetlen elemével sem array
Valid a bemenet átmegy az érvényesítésen ( feltételek esetén)

Szöveges bemenetek

A addText(), addPassword(), addTextArea(), addEmail(), addInteger(), addFloat() elemekre a következő szabályok közül néhányat is lehet alkalmazni:

MinLength minimális karakterlánc-hossz int
MaxLength maximális karakterlánc-hossz int
Length hossz a tartományban vagy pontos hossz pár [int, int] vagy int
Email érvényes e-mail cím
URL érvényes URL
Pattern megfelel a szabályos mintának string
PatternInsensitive mint a Pattern, de a nagy- és kisbetűket figyelmen kívül hagyja string
Integer egész szám
Numeric Integer álneve
Float egész vagy lebegőpontos szám
Min az egész szám értékének minimuma int|float
Max az egész szám értékének maximuma int|float
Range érték a tartományban pár [int|float, int|float]

A Integer, Numeric és Float szabályok automatikusan egész számra (illetve lebegőszámra) konvertálják az értéket. Továbbá a URL szabály elfogad egy séma nélküli címet is (pl. nette.org), és kiegészíti a sémát (https://nette.org). A Pattern és a PatternInsensitive kifejezéseknek a teljes értékre érvényesnek kell lenniük, azaz mintha a ^ and $ karakterekbe lenne csomagolva.

Tételek száma

A addMultiUpload(), addCheckboxList(), addMultiSelect() elemek esetében a következő szabályokkal is korlátozhatja a kiválasztott elemek vagy feltöltött fájlok számát:

MinLength minimális szám int
MaxLength maximális szám int
Length szám tartományon belül vagy pontos szám párok [int, int] vagy int

Fájl feltöltés

A addUpload(), addMultiUpload() vezérlőkre a következő szabályok is alkalmazhatók:

MaxFileSize maximális fájlméret bájtban int
MimeType MIME-típus, elfogadja a helyettesítő karaktereket ('video/*') string|string[]
Image a feltöltött fájl JPEG, PNG, GIF, WebP
Pattern a fájl neve megfelel a reguláris kifejezésnek string
PatternInsensitive mint a Pattern, de a nagy- és kisbetűket nem érzékeli string

A MimeType és a Image a fileinfo PHP kiterjesztést igényli. Az, hogy egy fájl vagy kép a kívánt típusba tartozik-e, az aláírás alapján állapítható meg. A teljes fájl sértetlenségét nem ellenőrzi a rendszer. Azt, hogy egy kép nem sérült-e, például úgy lehet megállapítani, ha megpróbáljuk betölteni.

Hibaüzenetek

A Pattern és a PatternInsensitive kivételével minden előre definiált szabály rendelkezik alapértelmezett hibaüzenettel, így ezek elhagyhatók. Az összes testreszabott üzenet átadásával és megfogalmazásával azonban felhasználóbarátabbá teszi az űrlapot.

Az alapértelmezett üzeneteket a forms:configuration-ban, a Nette\Forms\Validator::$messages tömbben lévő szövegek módosításával vagy a translator használatával módosíthatja.

A hibaüzenetek szövegében a következő helyettesítő karakterek használhatók:

%d fokozatosan helyettesíti a szabályokat az argumentumok után.
%n$d az n-edik szabály argumentumával helyettesíti.
%label a mező címkéjével helyettesíti (kettőspont nélkül)
%name a mező nevével helyettesíti (pl. name).
%value a felhasználó által megadott értékkel helyettesíti.
$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]);

Feltételek

Az érvényesítési szabályok mellett feltételek is beállíthatók. Ezek beállítása hasonlóan történik, mint a szabályoké, azonban a addCondition() helyett a addRule() címet használjuk, és természetesen hibaüzenet nélkül hagyjuk (a feltétel csak kérdez):

$form->addPassword('password', 'Jelszó:')
	// ha a jelszó nem hosszabb 8 karakternél ...
	->addCondition($form::MaxLength, 8)
		// ... akkor egy számot kell tartalmaznia.
		->addRule($form::Pattern, 'Számot kell tartalmaznia', '.*[0-9].*');

A feltétel a addConditionOn() segítségével az aktuális elemtől eltérő elemhez is kapcsolható. Az első paraméter a mezőre való hivatkozás. A következő esetben az e-mail csak akkor lesz kötelező, ha a jelölőnégyzet be van jelölve (azaz az értéke true):

$form->addCheckbox('newsletters', 'send me newsletters');

$form->addEmail('email', 'Email:')
	// ha a jelölőnégyzet be van jelölve ...
	->addConditionOn($form['newsletters'], $form::Equal, true)
		// ... megköveteli az email
		->setRequired('Adja meg az e-mail címét');

A feltételek a elseCondition() és a endCondition() metódusokkal összetett struktúrákba csoportosíthatók.

$form->addText(/* ... */)
	->addCondition(/* ... */) // ha az első feltétel teljesül.
		->addConditionOn(/* ... */) // és a második feltétel egy másik elemre is.
			->addRule(/* ... */) // megköveteli ezt a szabályt
		->elseCondition() // ha a második feltétel nem teljesül
			->addRule(/* ... */) // szükség van ezekre a szabályokra.
			->addRule(/* ... */)
		->endCondition() // visszatérünk az első feltételhez
		->addRule(/* ... */);

A Nette-ben nagyon egyszerűen reagálhatunk egy feltétel teljesülésére vagy nem teljesülésére a JavaScript oldalán a toggle() metódus segítségével, lásd Dynamic JavaScript.

Hivatkozások a vezérlők között

A szabály vagy feltétel argumentum lehet hivatkozás egy másik elemre. Például dinamikusan érvényesítheti, hogy a text annyi karaktert tartalmazzon, ahány karakter a length mező értéke:

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

Egyéni szabályok és feltételek

Néha olyan helyzetbe kerülünk, amikor a Nette beépített érvényesítési szabályai nem elegendőek, és a felhasználó adatait saját módon kell érvényesítenünk. A Nette-ben ez nagyon egyszerű!

A addRule() vagy a addCondition() metódusok első paramétereként bármilyen visszahívást átadhatunk. A callback első paraméterként magát az elemet fogadja el, és egy bóluszi értéket ad vissza, amely jelzi, hogy az érvényesítés sikeres volt-e. Szabály hozzáadásakor a addRule() segítségével további argumentumok adhatók át, amelyek második paraméterként kerülnek átadásra.

Az egyéni érvényesítőkészlet tehát statikus metódusokkal rendelkező osztályként hozható létre:

class MyValidators
{
	// teszteli, hogy az érték osztható-e az argumentummal.
	public static function validateDivisibility(BaseControl $input, $arg): bool
	{
		return $input->getValue() % $arg === 0;
	}

	public static function validateEmailDomain(BaseControl $input, $domain)
	{
		// további validátorok
	}
}

A használat nagyon egyszerű:

$form->addInteger('num')
	->addRule(
		[MyValidators::class, 'validateDivisibility'],
		'The value must be a multiple of %d',
		8,
	);

Egyéni érvényesítési szabályokat is hozzá lehet adni a JavaScripthez. Az egyetlen követelmény, hogy a szabály statikus metódus legyen. Nevét a JavaScript-érvényesítő számára az osztály neve (backslashes nélkül) \, the underscore _, és a metódus neve egymás mellé fűzésével hozzuk létre. Például írjuk a App\MyValidators::validateDivisibility -t AppMyValidators_validateDivisibility néven, és adjuk hozzá a Nette.validators objektumhoz:

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

Esemény onValidate

Az űrlap elküldése után az érvényesítés a addRule() által hozzáadott egyedi szabályok ellenőrzésével, majd a onValidateesemény meghívásával történik. Kezelője további érvényesítésre használható, jellemzően több űrlapelem értékének helyes kombinációjának ellenőrzésére.

Ha hibát észlel, azt a addError() metódus segítségével továbbítja az űrlapnak. Ezt vagy egy adott elemen, vagy közvetlenül az űrlapon lehet meghívni.

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('Ez a kombináció nem lehetséges.');
	}
}

Hibák feldolgozása

Sok esetben egy érvényes űrlap feldolgozása közben fedezünk fel hibát, például amikor új bejegyzést írunk az adatbázisba, és egy duplikált kulcsot találunk. Ebben az esetben a addError() metódus segítségével adjuk vissza a hibát az űrlapnak. Ezt vagy egy adott elemen, vagy közvetlenül az űrlapon hívhatjuk meg:

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

Ha lehetséges, javasoljuk, hogy a hibát közvetlenül az űrlap elemhez adjuk hozzá, mivel az alapértelmezett renderelő használata esetén a hiba mellette fog megjelenni.

$form['date']->addError('Sorry, this date is already taken.');

A addError() többször is meghívható, hogy több hibaüzenetet adjon át egy űrlapnak vagy elemnek. Ezeket a getErrors() segítségével kapja meg.

Vegye figyelembe, hogy a $form->getErrors() az összes hibaüzenet összefoglalóját adja vissza, még a közvetlenül az egyes elemeknek átadottakat is, nem csak közvetlenül az űrlapnak. A csak az űrlapnak átadott hibaüzeneteket a $form->getOwnErrors() segítségével kapjuk meg.

A beviteli értékek módosítása

A addFilter() módszerrel módosíthatjuk a felhasználó által megadott értéket. Ebben a példában megtűrjük és eltávolítjuk a szóközöket az irányítószámban:

$form->addText('zip', 'Irányítószám:')
	->addFilter(function ($value) {
		return str_replace(' ', '', $value); // eltávolítjuk a szóközöket az irányítószámból.
	})
	->addRule($form::Pattern, 'Az irányítószám nem ötjegyű', '\d{5}');

A szűrő az érvényesítési szabályok és feltételek között szerepel, ezért függ a módszerek sorrendjétől, azaz a szűrő és a szabály meghívása ugyanabban a sorrendben történik, mint a addFilter() és a addRule() módszerek sorrendje.

JavaScript érvényesítés

Az érvényesítési szabályok és feltételek nyelve nagy teljesítményű. Annak ellenére, hogy minden konstrukció szerver- és kliensoldalon egyaránt működik, JavaScriptben. A szabályok átadása HTML-attribútumokban történik data-nette-rules JSON-ként. Magát az érvényesítést egy másik szkript kezeli, amely az űrlap összes submit eseményét megakasztja, iterálja az összes bemenetet és lefuttatja a megfelelő érvényesítéseket.

Ez a szkript a netteForms.js, amely több lehetséges forrásból is elérhető:

A szkriptet közvetlenül a CDN-ből származó HTML-oldalba ágyazhatja be:

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

Vagy másolja be helyileg a projekt nyilvános mappájába (pl. a vendor/nette/forms/src/assets/netteForms.min.js):

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

Vagy telepítse az npm segítségével:

npm install nette-forms

Aztán töltsd be és futtasd:

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

Alternatívaként közvetlenül a vendor mappából is betöltheti:

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

Dinamikus JavaScript

Csak akkor szeretné megjeleníteni a cím mezőt, ha a felhasználó úgy dönt, hogy postai úton küldi el az árut? Nem probléma. A kulcs a addCondition() & toggle() metóduspár:

$form->addCheckbox('send_it')
	->addCondition($form::Equal, true)
		->toggle('#address-container');

Ez a kód azt mondja, hogy ha a feltétel teljesül, vagyis ha a jelölőnégyzet be van jelölve, akkor a #address-container HTML-elem láthatóvá válik. És fordítva. Tehát a címzett címét tartalmazó űrlapelemeket egy ilyen azonosítóval rendelkező konténerbe helyezzük, és amikor a jelölőnégyzetre kattintunk, elrejtjük vagy megjelenítjük őket. Ezt a netteForms.js szkript kezeli.

A toggle() metódusnak argumentumként bármilyen szelektor átadható. Történelmi okokból a más speciális karaktereket nem tartalmazó alfanumerikus karakterláncot elemazonosítóként kezeljük, ugyanúgy, mintha a # character. The second optional parameter allows us to reverse the behavior, i.e. if we used toggle('#address-container', false) lenne előtte, az elem csak akkor jelenne meg, ha a jelölőnégyzet nincs bejelölve.

Az alapértelmezett JavaScript implementáció megváltoztatja az elemek hidden tulajdonságát. A viselkedést azonban könnyen megváltoztathatjuk, például egy animáció hozzáadásával. Csak írjuk felül a Nette.toggle metódust JavaScriptben egy egyéni megoldással:

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

Az érvényesítés letiltása

Bizonyos esetekben le kell tiltani az érvényesítést. Ha egy beküldőgombnak nem kellene érvényesítést futtatnia a beküldés után (például Mondás vagy Közlemény gomb), akkor az érvényesítést a $submit->setValidationScope([]) meghívásával tilthatja le. Az űrlapot részlegesen is érvényesítheti az érvényesítendő elemek megadásával.

$form->addText('name')
	->setRequired();

$details = $form->addContainer('details');
$details->addInteger('age')
	->setRequired('age');
$details->addInteger('age2')
	->setRequired('age2');

$form->addSubmit('send1'); // Az egész űrlap hitelesítése
$form->addSubmit('send2')
	->setValidationScope([]); // Nem érvényesít semmit.
$form->addSubmit('send3')
	->setValidationScope([$form['name']]); // Csak a 'name' mezőt érvényesíti.
$form->addSubmit('send4')
	->setValidationScope([$form['details']['age']]); // Csak az 'age' mezőt érvényesíti.
$form->addSubmit('send5')
	->setValidationScope([$form['details']]); // Validálja a 'details' konténert.

Az onValidate esemény az űrlapon mindig meghívásra kerül, és nem befolyásolja a setValidationScope. onValidate esemény a konténeren csak akkor hívódik meg, ha ez a konténer részleges érvényesítésre van megadva.