V minulém díle seriálu o Nette Framework jsme se pustili do tvorby registračního formuláře. Výsledkem byl dobře fungující formulář s validací na straně prohlížeče i serveru, který navíc framework transparentně ochránil před vložením kontrolních znaků nebo neplatných řetězců útočníkem.
Vraťme se k políčku pro zadávání e-mailu. Tomu jsme nastavili validační pravidlo, které zkontroluje, zda je vložená adresa platná:
$form->addText('email', 'E-mail:')
->addRule(Form::EMAIL, 'E-mailová adresa není platná');
Protože prázdný řetězec pochopitelně není platnou emailovou adresou, tak nevyplnění e-mailu povede k chybové hlášce E-mailová adresa není platná, což není právě uživatelsky přívětivé a bylo by proto vhodné přidat na začátek pravidlo Form::FILLED
. Co ale v případě, že chceme e-mailovou adresu mít nepovinnou, tj. kontrolovat její platnost jen v případě, že ji uživatel vyplnil? Tohle lze vyřešit přes tzv. validační podmínky. Ty se zapisují podobně jako pravidla, jen místo addRule
použijeme metodu addCondition
(chybová hláška se pochopitelně neuvádí):
$form->addText('email', 'E-mail:')
->addCondition(Form::FILLED) // podmínka: pokud je e-mail vyplněn
->addRule(Form::EMAIL, 'E-mailová adresa není platná'); // pak musí být platný
Podmínku je možné vázat i na jiný prvek, než ten aktuální. Stačí addCondition
nahradit za addConditionOn
a jako první parametr uvést odvolávku na jiný prvek. V tomto případě se bude e-mail vyžadovat tehdy, zaškrtne-li se checkbox (tj. jeho logická hodnota bude TRUE):
$form->addCheckbox('promo', 'zasílejte mi reklamu');
$form->addText('email', 'E-mail:')
->addConditionOn($form['promo'], Form::EQUAL, TRUE) // podmínka: pokud je checkbox zaškrtnut
->addRule(Form::FILLED, 'Zadejte e-mailovou adresu'); // pak musí být e-mail zadaný
Pravidla a podmínky je možné negovat přidáním ~
, tj. addRule(~Form::EMAIL, ...)
. Také lze z podmínek vytvářet komplexní struktury za pomoci metod elseCondition()
a endCondition()
.
Jak vidíte, jazyk pro formulování podmínek a pravidel je velice silný. Výhodou je, že framework podle něj provede nejen validaci na straně serveru, ale vygeneruje i javascriptovou podobu. Disponuje celou řadou předdefinovaných validačních konstant:
Obecné pravidla | |
---|---|
Form::EQUAL |
test rovnosti |
Form::IS_IN |
testuje, zda hodnota spadá do výčtu hodnot |
Form::FILLED |
je prvek vyplněn? |
Form::VALID |
je prvek vyplněn správně? |
Pro tlačítka | |
---|---|
Form::SUBMITTED |
bylo tlačítko stisknuto? |
Pro textové políčka | |
---|---|
Form::MIN_LENGTH |
minimální délka |
Form::MAX_LENGTH |
maximální délka |
Form::LENGTH |
délka |
Form::EMAIL |
je hodnota platná e-mailová adresa? |
Form::URL |
je hodnota absolutní URL? |
Form::REGEXP |
test oproti regulárnímu výrazu |
Form::INTEGER |
je hodnota celočíselná? |
Form::FLOAT |
je hodnota číslo? |
Form::RANGE |
je hodnota v daném rozsahu? |
Nahrávání souborů | |
---|---|
Form::MAX_FILE_SIZE |
maximální velikost souboru |
Form::MIME_TYPE |
ověření MIME type |
Nic vám ovšem nebrání přidat si vlastní validátory:
// uživatelský validátor: testuje, zda je hodnota dělitelná argumentemfunction myValidator($item, $arg)
{
return $item->getValue() % $arg === 0;
}
$form->addText('number', 'Číslo:')
->addRule('myValidator', 'Číslo musí být dělitelné %d.', 8);
Prázdné hodnoty
Někdy se formulářovým políčkům nastavuje výchozí hodnota, která plní čistě vizuální úlohu. Příkladem je třeba vyhledávací formulář s popiskem Vyhledat přímo v textovém políčku. Jiným případem je políčko na zadání e-mailu, kde je předvyplněn zavináč, protože uživatelé mívají problém tento znak na klávesnici napsat.
V obou případech jde o hodnotu, kterou po odeslání formuláře nechceme v získaných datech mít. Vlastně ji musíme odfiltrovat už před validací, protože jinak nemusí proběhnout podle očekávání. Například podmínka Form::FILLED
může být vyhodnocena jako splněná, i když prvek obsahuje jen tuto speciální hodnotu.
Nette Framework nabízí řešení v podobě tzv. „prázdné hodnoty“, kterou nastavíme metodou setEmptyValue()
. Kompletní kód pro nepovinný zadávací prvek s e-mailovým políčkem a předvyplněným zavináčem bude vypadat takto:
$form->addText('email', 'E-mail:')
->setEmptyValue('@') // zavináč bude předvyplněn
->addCondition(Form::FILLED) // podmínka: pokud je e-mail vyplněn
->addRule(Form::EMAIL, 'E-mailová adresa není platná'); // pak musí být platný
Pokud uživatel odešle formulář a prvek email
bude obsahovat předvyplněný zavináč, v datech získaných metodou getValues()
bude prázdný řetězec.
Prázdné hodnoty v select boxech
U select boxů často mívá první položka také speciální význam, slouží jako výzva k akci. V našem formuláři máme povinný prvek country
pro uvedení země. Pole hodnot můžeme rozšířit o výzvu:
$countries = array(
'Zvolte zemi', // <-- výzva k akci
'Evropa' => array(
'CZ' => 'Česká republika',
'FR' => 'Francie',
'DE' => 'Německo',
'SK' => 'Slovensko',
'GB' => 'Velká Británie',
),
'AU' => 'Austrálie',
'CA' => 'Kanada',
'?' => 'jiná',
);
Aby však validace fungovala podle očekávání, musíme prvku nastavit, že první položka má tento speciální význam a při validaci je potřeba ji přeskakovat. K tomu slouží metoda skipFirst()
:
$form->addSelect('country', 'Země:', $countries)
->skipFirst()
->addRule(Form::FILLED, 'Vyberte zemi');
Pokud nyní uživatel odešle formulář a jako země bude vybrána položka „Zvolte zemi“, zobrazí se uživateli chybová hláška „Vyberte zemi.“
Cross-Site Request Forgery
Nette Framework ochrání vaše aplikace před útokem Cross-Site Request Forgery (CSRF). Stačí k tomu vynaložit minimální úsilí:
$form->addProtection('Vypršel ochranný časový limit, odešlete prosím formulář ještě jednou');
A v tuto chvíli je váš formulář chráněn proti CSRF. Tedy vedle automatické ochrany proti celé řadě dalších útoků (XSS, UTF-8 attack, …).
Vylepšený zdrojový kód formuláře si můžete opět stáhnout.
Příště se podíváme na možnosti vykreslování formulářů.
Autor článku je vývojář na volné noze, specializuje se na návrh a programování moderních webových aplikací. Vyvíjí open-source knihovny Texy, dibi a Nette Framework a pravidelně pořádá školení pro tvůrce webových aplikací, které od podzimu 2009 nabídne kurz vývoje AJAXových aplikací.
Přehled komentářů