Űrlap validáció
Kötelező elemek
A kötelező elemeket a setRequired()
metódussal jelöljük meg, amelynek argumentuma a hibaüzenetek hibaüzenet szövege, amely akkor jelenik meg, ha a felhasználó nem tölti ki az
elemet. Ha nem adunk meg argumentumot, az alapértelmezett hibaüzenet kerül felhasználásra.
$form->addText('name', 'Név:')
->setRequired('Kérjük, adja meg a nevét');
Szabályok
Validációs szabályokat az elemekhez az addRule()
metódussal adunk hozzá. Az első paraméter a szabály, a
második a hibaüzenetek hibaüzenet szövege, a harmadik pedig a validációs szabály
argumentuma.
$form->addPassword('password', 'Jelszó:')
->addRule($form::MinLength, 'A jelszónak legalább %d karakter hosszúnak kell lennie', 8);
A validációs 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állyal rendelkezik, amelyek nevei a Nette\Forms\Form
osztály konstansai.
Minden elemhez használhatjuk ezeket a szabályokat:
konstans | leírás | argumentum típusa |
---|---|---|
Required |
kötelező elem, alias a setRequired() számára |
– |
Filled |
kötelező elem, alias a setRequired() számára |
– |
Blank |
az elem nem lehet kitöltve | – |
Equal |
az érték megegyezik a paraméterrel | mixed |
NotEqual |
az érték nem egyezik meg a paraméterrel | mixed |
IsIn |
az érték megegyezik a tömb valamelyik elemével | array |
IsNotIn |
az érték nem egyezik meg a tömb egyik elemével sem | array |
Valid |
az elem helyesen van kitöltve? (feltételek számára) | – |
Szöveges bevitelek
Az addText()
, addPassword()
, addTextArea()
, addEmail()
,
addInteger()
, addFloat()
elemekhez használhatók a következő szabályok is:
MinLength |
minimális szöveghossz | int |
MaxLength |
maximális szöveghossz | int |
Length |
hossz tartományban vagy pontos hossz | pár [int, int] vagy int |
Email |
érvényes e-mail cím | – |
URL |
abszolút URL | – |
Pattern |
megfelel a reguláris kifejezésnek | string |
PatternInsensitive |
mint a Pattern , de kis- és nagybetű érzéketlen |
string |
Integer |
egész szám érték | – |
Numeric |
alias az Integer számára |
– |
Float |
szám | – |
Min |
numerikus elem minimális értéke | int|float |
Max |
numerikus elem maximális értéke | int|float |
Range |
érték tartományban | pár [int|float, int|float] |
Az Integer
, Numeric
és Float
validációs szabályok azonnal átalakítják az
értéket integerre, illetve floatra. Továbbá az URL
szabály elfogadja a 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
PatternIcase
kifejezésnek az egész értékre kell érvényesnek lennie, azaz mintha ^
és
$
karakterekkel lenne körbevéve.
Elemek száma
Az addMultiUpload()
, addCheckboxList()
, addMultiSelect()
elemekhez használhatók a
következő szabályok is a kiválasztott elemek, illetve feltöltött fájlok számának korlátozására:
MinLength |
minimális szám | int |
MaxLength |
maximális szám | int |
Length |
szám tartományban vagy pontos szám | pár [int, int] vagy int |
Fájlfeltöltések
Az addUpload()
, addMultiUpload()
elemekhez használhatók a következő szabályok is:
MaxFileSize |
maximális fájlméret bájtban | int |
MimeType |
MIME típus, helyettesítő karakterek engedélyezettek ('video/*' ) |
string|string[] |
Image |
JPEG, PNG, GIF, WebP, AVIF kép | – |
Pattern |
a fájlnév megfelel a reguláris kifejezésnek | string |
PatternInsensitive |
mint a Pattern , de kis- és nagybetű érzéketlen |
string |
A MimeType
és Image
szabályokhoz szükség van a fileinfo
PHP kiterjesztésre. Azt,
hogy a fájl vagy kép a kívánt típusú-e, az aláírása alapján észlelik, és nem ellenőrzik az egész fájl
integritását. Azt, hogy a kép nem sérült-e, például a betöltésével lehet megállapítani.
Hibaüzenetek
Minden előre definiált szabálynak, kivéve a Pattern
és PatternInsensitive
szabályokat, van
alapértelmezett hibaüzenete, így azt el lehet hagyni. Azonban az összes üzenet testreszabott megadásával és
megfogalmazásával felhasználóbarátabbá teheti az űrlapot.
Az alapértelmezett üzeneteket megváltoztathatja a konfigurációban, a Nette\Forms\Validator::$messages
tömb
szövegeinek módosításával, vagy a fordító
használatával.
A hibaüzenetek szövegében a következő helyettesítő stringek használhatók:
%d |
sorban helyettesíti a szabály argumentumaival |
%n$d |
helyettesíti a szabály n-edik argumentumával |
%label |
helyettesíti az elem címkéjével (kettőspont nélkül) |
%name |
helyettesíti az elem nevével (pl. name ) |
%value |
helyettesíti a felhasználó által beírt értékkel |
$form->addText('name', 'Név:')
->setRequired('Kérjük, töltse ki a %label mezőt');
$form->addInteger('id', 'ID:')
->addRule($form::Range, 'legalább %d és legfeljebb %d', [5, 10]);
$form->addInteger('id', 'ID:')
->addRule($form::Range, 'legfeljebb %2$d és legalább %1$d', [5, 10]);
Feltételek
A szabályokon kívül feltételeket is hozzáadhatunk. Ezeket hasonlóan írjuk, mint a szabályokat, csak az
addRule()
helyett az addCondition()
metódust használjuk, és természetesen nem adunk meg
hibaüzenetet (a feltétel csak kérdez):
$form->addPassword('password', 'Jelszó:')
// ha a jelszó nem hosszabb 8 karakternél
->addCondition($form::MaxLength, 8)
// akkor számjegyet kell tartalmaznia
->addRule($form::Pattern, 'Számjegyet kell tartalmaznia', '.*[0-9].*');
A feltételt az aktuális elemen kívül más elemhez is köthetjük az addConditionOn()
segítségével. Első
paraméterként az elemre való hivatkozást adjuk meg. Ebben a példában az e-mail csak akkor lesz kötelező, ha a checkbox be
van jelölve (az értéke true lesz):
$form->addCheckbox('newsletters', 'küldjenek nekem hírleveleket');
$form->addEmail('email', 'E-mail:')
// ha a checkbox be van jelölve
->addConditionOn($form['newsletters'], $form::Equal, true)
// akkor követelje meg az e-mailt
->setRequired('Adja meg az e-mail címét');
A feltételekből komplex struktúrákat hozhatunk létre az elseCondition()
és endCondition()
segítségével:
$form->addText(/* ... */)
->addCondition(/* ... */) // ha az első feltétel teljesül
->addConditionOn(/* ... */) // és a második feltétel egy másik elemen
->addRule(/* ... */) // követelje meg ezt a szabályt
->elseCondition() // ha a második feltétel nem teljesül
->addRule(/* ... */) // követelje meg ezeket a szabályokat
->addRule(/* ... */)
->endCondition() // visszatérünk az első feltételhez
->addRule(/* ... */);
A Nette-ben nagyon könnyen reagálhatunk a feltétel teljesülésére vagy nem teljesülésére JavaScript oldalon is a
toggle()
metódus segítségével, lásd dinamikus JavaScript.
Hivatkozás más elemre
Szabály vagy feltétel argumentumaként más űrlap elemet is átadhatunk. A szabály ezután a felhasználó által később
a böngészőben beírt értéket használja. Így például dinamikusan validálhatjuk, hogy a password
elem
ugyanazt a stringet tartalmazza-e, mint a password_confirm
elem:
$form->addPassword('password', 'Jelszó');
$form->addPassword('password_confirm', 'Jelszó megerősítése')
->addRule($form::Equal, 'A megadott jelszavak nem egyeznek', $form['password']);
Egyéni szabályok és feltételek
Néha olyan helyzetbe kerülünk, amikor a Nette beépített validációs szabályai nem elegendőek, és a felhasználótól származó adatokat a saját módunkon kell validálnunk. A Nette-ben ez nagyon egyszerű!
Az addRule()
vagy addCondition()
metódusoknak első paraméterként tetszőleges callbacket adhatunk
át. Ez első paraméterként magát az elemet kapja, és boolean értéket ad vissza, amely meghatározza, hogy a validáció
rendben lezajlott-e. Az addRule()
segítségével történő szabály hozzáadásakor további argumentumokat is
megadhatunk, ezeket aztán második paraméterként adjuk át.
Így létrehozhatunk egy saját validátor készletet osztályként statikus metódusokkal:
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 ezután nagyon egyszerű:
$form->addInteger('num')
->addRule(
[MyValidators::class, 'validateDivisibility'],
'Az értéknek a %d szám többszörösének kell lennie',
8,
);
Egyéni validációs szabályokat JavaScripthez is hozzáadhatunk. A feltétel az, hogy a szabály statikus metódus legyen.
A neve a JavaScript validátor számára az osztály nevének a visszaperjelek \
nélküli, aláhúzásjel
_
és a metódus nevének összekapcsolásával jön létre. Pl. az
App\MyValidators::validateDivisibility
-t AppMyValidators_validateDivisibility
-ként írjuk, és
hozzáadjuk a Nette.validators
objektumhoz:
Nette.validators['AppMyValidators_validateDivisibility'] = (elem, args, val) => {
return val % args === 0;
};
onValidate esemény
Az űrlap elküldése után validáció történik, amely során ellenőrzésre kerülnek az addRule()
segítségével hozzáadott egyes szabályok, majd kiváltódik az esemény onValidate
. Ennek a kezelőjét (handler)
kiegészítő validációra használhatjuk, tipikusan az értékek helyes kombinációjának ellenőrzésére több űrlap
elemben.
Ha hibát észlelünk, azt az addError()
metódussal adjuk át az űrlapnak. Ezt vagy egy konkrét elemen, vagy
közvetlenül az űrlapon hívhatjuk meg.
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 a feldolgozás során
Sok esetben csak akkor értesülünk a hibáról, amikor az érvényes űrlapot dolgozzuk fel, például új elemet írunk az
adatbázisba, és kulcsduplikációba ütközünk. Ebben az esetben a hibát ismét az addError()
metódussal adjuk
át az űrlapnak. Ezt vagy egy konkrét 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('Érvénytelen jelszó.');
}
}
Ha lehetséges, javasoljuk, hogy a hibát közvetlenül az űrlap eleméhez csatolja, mert az alapértelmezett renderer használatakor mellette jelenik meg.
$form['date']->addError('Elnézést, de ez a dátum már foglalt.');
Az addError()
metódust ismételten meghívhatja, és így több hibaüzenetet adhat át az űrlapnak vagy
elemnek. Ezeket a getErrors()
segítségével szerezheti meg.
Figyelem, a $form->getErrors()
az összes hibaüzenet összegzését adja vissza, beleértve azokat is,
amelyeket közvetlenül az egyes elemekhez adtak át, nem csak közvetlenül az űrlaphoz. A csak az űrlaphoz átadott
hibaüzeneteket a $form->getOwnErrors()
segítségével szerezheti meg.
Bemenet módosítása
Az addFilter()
metódus segítségével módosíthatjuk a felhasználó által beírt értéket. Ebben a
példában toleráljuk é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 öt számjegyű', '\d{5}');
A szűrő beépül a validációs szabályok és feltételek közé, tehát a metódusok sorrendje számít, azaz a szűrő
és a szabály abban a sorrendben hívódik meg, ahogy az addFilter()
és addRule()
metódusok
sorrendje van.
JavaScript validáció
A feltételek és szabályok megfogalmazásának nyelve nagyon erős. Minden konstrukció működik mind a szerveroldalon,
mind a JavaScript oldalon. HTML attribútumokban data-nette-rules
JSON formátumban kerülnek átadásra. Magát a
validációt pedig egy szkript végzi, amely elfogja az űrlap submit
eseményét, végigmegy az egyes elemeken, és
végrehajtja a megfelelő validációt.
Ez a szkript a netteForms.js
, és több lehetséges forrásból érhető el:
A szkriptet közvetlenül beillesztheti a HTML oldalba egy CDN-ről:
<script src="https://unpkg.com/nette-forms@3"></script>
Vagy másolja helyileg a projekt nyilvános mappájába (pl. a vendor/nette/forms/src/assets/netteForms.min.js
fájlból):
<script src="/path/to/netteForms.min.js"></script>
Vagy telepítse npm segítségével:
npm install nette-forms
Majd töltse be és futtassa:
import netteForms from 'nette-forms';
netteForms.initOnLoad();
Alternatívaként betöltheti közvetlenül a vendor
mappából:
import netteForms from '../path/to/vendor/nette/forms/src/assets/netteForms.js';
netteForms.initOnLoad();
Dinamikus JavaScript
Szeretné megjeleníteni a cím megadására szolgáló mezőket csak akkor, ha a felhasználó postai kézbesítést választ?
Semmi probléma. A kulcs az addCondition()
& toggle()
metóduspár:
$form->addCheckbox('send_it')
->addCondition($form::Equal, true)
->toggle('#address-container');
Ez a kód azt mondja, hogy amikor a feltétel teljesül, tehát amikor a checkbox be van jelölve, a
#address-container
HTML elem látható lesz. És fordítva. A címzett címét tartalmazó űrlap elemeket tehát
egy ilyen ID-jű konténerbe helyezzük, és a checkboxra kattintva elrejtődnek vagy megjelennek. Ezt a
netteForms.js
szkript biztosítja.
A toggle()
metódus argumentumaként tetszőleges selectort adhatunk át. Történelmi okokból az alfanumerikus
string további speciális karakterek nélkül elem ID-ként értelmeződik, tehát ugyanúgy, mintha #
karakter
előzné meg. A második, nem kötelező paraméter lehetővé teszi a viselkedés megfordítását, azaz ha a
toggle('#address-container', false)
-t használnánk, az elem éppen ellenkezőleg, csak akkor jelenne meg, ha a
checkbox nem lenne bejelölve.
Az alapértelmezett implementáció JavaScriptben az elemek hidden
propertyjét változtatja meg. A viselkedést
azonban könnyen megváltoztathatjuk, például animációt adhatunk hozzá. Elég JavaScriptben felülírni a
Nette.toggle
metódust saját megoldással:
Nette.toggle = (selector, visible, srcElement, event) => {
document.querySelectorAll(selector).forEach((el) => {
// elrejtjük vagy megjelenítjük az 'el'-t a 'visible' értékétől függően
});
};
Validáció kikapcsolása
Néha hasznos lehet a validáció kikapcsolása. Ha a küldés gomb megnyomása nem kell, hogy validációt végezzen (alkalmas
Cancel vagy Preview gombokhoz), kikapcsoljuk a $submit->setValidationScope([])
metódussal. Ha csak
részleges validációt kell végeznie, megadhatjuk, mely mezők vagy űrlap konténerek validálódjanak.
$form->addText('name')
->setRequired();
$details = $form->addContainer('details');
$details->addInteger('age')
->setRequired('age');
$details->addInteger('age2')
->setRequired('age2');
$form->addSubmit('send1'); // Az egész űrlapot validálja
$form->addSubmit('send2')
->setValidationScope([]); // Egyáltalán nem validál
$form->addSubmit('send3')
->setValidationScope([$form['name']]); // Csak a name elemet validálja
$form->addSubmit('send4')
->setValidationScope([$form['details']['age']]); // Csak az age elemet validálja
$form->addSubmit('send5')
->setValidationScope([$form['details']]); // A details konténert validálja
A setValidationScope
nem befolyásolja a onValidate esemény eseményt az
űrlapon, amely mindig meghívásra kerül. A konténer onValidate
eseménye csak akkor kerül kiváltásra, ha ez a
konténer részleges validációra van megjelölve.