Ještě než si napíšeme v Nette Framework první formulář, je potřeba říci, že formuláře jsou sice dobří sluhové, ale zlí páni. Jestliže jsem se o sessions zmiňoval jako o potenciálním zdroji největších bezpečnostních děr, o formulářích musím prohlásit to stejné. Opět ale platí, že Nette Framework klade velký důraz na bezpečnost aplikací, a proto vynakládá značné úsilí i pro zabezpečení formulářů. Dělá to zcela transparentně, nevyžaduje nic manuálně nastavovat a troufám si říci, že v této oblasti má velký náskok před ostatními frameworky.
Nette Framework ochrání vaše aplikace před útokem Cross-Site Request Forgery (CSRF), odfiltruje ze vstupů kontrolní znaky, ujistí se, že všechny textové vstupy představují validní UTF-8 řetězce, že položky označené v select boxech skutečně patří mezi nabízené, automaticky ořeže mezery na jednořádkovém textovém políčku atd.
Registrační formulář
Pojďme si vytvořit registrační formulář (kód si můžete stáhnout):
require 'Netteloader.php';
// pokud používáte verzi pro PHP 5.3, odkomentujte následující řádek:
// use NetteFormsForm, NetteDebug;
Debug::enable();
$countries = array(
'Evropa' => array(
'CZ' => 'Česká republika',
'FR' => 'Francie',
'DE' => 'Německo',
'SK' => 'Slovensko',
'GB' => 'Velká Británie',
),
'AU' => 'Austrálie',
'CA' => 'Kanada',
'?' => 'jiná',
);
$sex = array(
'm' => 'muž',
'f' => 'žena',
);
$form = new Form;
$form->addText('name', 'Jméno:');
$form->addText('age', 'Věk:');
$form->addRadioList('gender', 'Pohlaví:', $sex);
$form->addText('email', 'E-mail:');
$form->addCheckbox('promo', 'zasílejte mi reklamu');
$form->addSelect('country', 'Země:', $countries);
$form->addPassword('password', 'Heslo:');
$form->addPassword('password2', 'Heslo pro kontrolu:');
$form->addSubmit('register', 'Registrovat');
echo $form;
Vykreslí se vám následující formulář:
Upozornění: skripty musí být uloženy v UTF-8.
Samotný kód je dostatečně samovysvětlující a ve spojení s obrázkem asi nepotřebuje dalšího komentáře. Snad jen dodám, že u každé metody addXyz() představuje první parametr interní identifikátor, tedy jakési ID prvku. K jednotlivým prvkům lze poté přistupovat pomocí hranatých závorek, podobně jako k prvkům pole. Takže třeba $form['name']
je objektem třídy NetteFormsTextInput
a představuje první položku formuláře.
Vykreslený formulář splňuje základní pravidlo přístupnosti – všechny popisky jsou označeny jako <label>
a provázané s formulářovým prvkem. Můžete tedy myší kliknout na popisku a kurzor se přesune do prvku. Zároveň jsou ošetřeny chyby prohlížečů (tedy vlastně prohlížeče Internet Explorer) týkající se select boxu: kliknutí na popisku nebo otočení kolečkem myši nesmaže výběr. HTML podoba formuláře se dá kompletně změnit, jak si ukážeme v dalším pokračování.
Už v prvním díle seriálu jsme si říkali o životním cyklu formuláře, který začíná zrozením (tedy definicí) formuláře, pokračuje testem na to, zda byl odeslán (is submitted?) a jestli je validní (is valid?), v případě kladných odpovědí vstupní data zpracujeme, v opačném případě jej zobrazíme uživateli.
Za definici formuláře tedy vložte kód:
// jestliže byl formulář odeslán
if ($form->isSubmitted()) {
// a jestliže jsou všechny položky vyplněny správně
if ($form->isValid()) {
echo '<h1>Formulář byl odeslán</h1>';
$values = $form->getValues();
Debug::dump($values);
exit;
}
} else {
// a jestliže nebyl odeslán, nastavíme výchozí hodnoty
$form->setDefaults(array(
'promo' => TRUE,
));}
Dotazem $form->isSubmitted()
lze detekovat první zobrazení formuláře – pokud vrací false, formulář nebyl odeslán a je tedy uživateli předložen poprvé. V takovém případě mu nastavíme výchozí hodnoty metodou setDefaults
. Výchozí hodnoty tvoří pole, kde jednotlivé klíče představují výše zmíněné ID prvků.
Pokud naopak formulář odeslán byl, je potřeba ještě metodou isValid()
ověřit, zda byl vyplněn korektně. Existují ale případy, kdy můžeme jednat i bez ověření validace – například pokud formulář obsahuje tlačítko Cancel
nebo Zpět
a toto bylo stisknuto. Zda byl vícetlačítkový formulář odeslán konkrétním tlačítkem, zjistíme dotazem např. if ($form['register']->isSubmittedBy())
.
Aby bylo ověřování validace smysluplné, musíme formuláři nastavit nějaká validační pravidla. K tomu složí metoda addRule()
, kde první argument říká, jakou vlastnost chceme ověřovat a druhý argument je text chybové hlášky. Asi nejčastěji se budete setkávat s pravidlem Form::FILLED
, které požaduje, aby prvek byl vyplněn (nebo měl zvolenou hodnotu v případě select boxu či radio listu):
$form->addText('name', 'Jméno:')
->addRule(Form::FILLED, 'Zadejte jméno');
Zajímavostí je, že Nette Framework automaticky detekuje, že prvek je povinný, a proto mu nastaví CSS třídu required
. Pokud stylem .required { color: darkred }
změníme prvkům barvu, hned se nám vykreslí takto:
Podobně budeme vyžadovat i povinné vyplnění věku, navíc přidáme kontrolu, zda jde o číslo ( Form::INTEGER
) a zda je v povoleném rozsahu ( Form::RANGE
). Zde využijeme třetí parametr metody addRule
, kterým předáme validátoru informaci o rozsahu:
$form->addText('age', 'Věk:')
->addRule(Form::FILLED, 'Zadejte věk')
->addRule(Form::INTEGER, 'Věk musí být číslo')
->addRule(Form::RANGE, 'Věk musí být v rozmezí od 5 do 120 let', array(5, 120));
Zde vzniká prostor pro drobný refactoring. V chybové hlášce a třetím parametru se duplikuje číselná informace, což není nikdy dobře. Navíc v dalším pokračování se dostaneme k překládání formulářů a pokud by se hláška obsahující čísla přeložila do více jazyků, ztížila by se případná úprava intervalu. Z toho důvodu je možné použít zástupné znaky v tomto formátu:
...
->addRule(Form::RANGE, 'Věk musí být v rozmezí od %d do %d let', array(5, 120));
Dalším políčkem, které budeme chtít validovat, je e-mailová adresa. Její platnost ověřuje pravidlo Form::EMAIL
.
$form->addText('email', 'E-mail:')
->addRule(Form::EMAIL, 'E-mailová adresa není platná');
Pravidlo Form::FILLED
přidáme prvkům country
, password
a password2
. Heslo budeme ještě kontrolovat na minimální délku ( Form::MIN_LENGTH
), opět s využitím zástupného znaku:
$form->addPassword('password', 'Heslo:')
->addRule(Form::FILLED, 'Zvolte si heslo')
->addRule(Form::MIN_LENGTH, 'Zadané heslo je příliš krátké, zvolte si heslo alespoň o %d znacích', 3);
A druhé heslo zkontroluje rovnost (tj. Form::EQUAL
) s heslem prvním (všimněte si odvolávky na první heslo):
$form->addPassword('password2', 'Heslo pro kontrolu:')
->addRule(Form::FILLED, 'Zadejte heslo ještě jednou pro kontrolu')
->addRule(Form::EQUAL, 'Zadané hesla se neshodují', $form['password']);
Hotový příklad si opět můžete stáhnout a vyzkoušet. Uvidíte, že kromě validace na straně serveru se automaticky dostala ke slovu i validace na straně prohlížeče (tj. javascriptová validace). Všimněte si, že po chybové zprávě se vždy kurzor umístí do příslušného políčka.
Uživatel se dostal do kolečka na křečka: dokud formulář nevyplní správně, je mu předkládán stále dokola s výpisem chyb.
Tímto ovšem validační možnosti zdaleka nekončí. Předností Nette Framework jsou tzv. validační podmínky, pomocí nichž uděláme políčko s e-mailem nepovinné. Ty najdete v příštím pokračování.
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ářů