Nette Framework: Neprůstřelné formuláře

Formuláře změnily Internet, z akademické sítě učinily komerční prostředí. Najednou bylo možno odesílat objednávky na e-shopech nebo poptávky přes kontaktní formuláře. Jak vypadá tvorba formuláře v Nette Framework?

Seriál: Začínáme s Nette Framework (17 dílů)

  1. Nette Framework: zvyšte svoji produktivitu 10.3.2009
  2. Nette Framework: Odvšivujeme 17.3.2009
  3. Nette Framework: MVC & MVP 24.3.2009
  4. Nette Framework: Refactoring 31.3.2009
  5. Nette Framework: Chytré šablony 7.4.2009
  6. Nette Framework: adresářová struktura aplikace 14.4.2009
  7. Nette Framework: AJAX 21.4.2009
  8. Nette Framework: AJAX (pokračování) 28.4.2009
  9. Nette Framework: AJAX (dokončení) 5.5.2009
  10. Nette Framework: Sessions 12.5.2009
  11. Nette Framework: Přihlašování uživatelů 19.5.2009
  12. Nette Framework: Ověřování oprávnění a role 26.5.2009
  13. Nette Framework: Neprůstřelné formuláře 2.6.2009
  14. Nette Framework: Neprůstřelné formuláře II 9.6.2009
  15. Nette Framework: Neprůstřelné formuláře III 16.6.2009
  16. Nette Framework: Cache 23.6.2009
  17. Nette Framework: Co se do seriálu nevešlo? 30.6.2009

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ář:

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

Nette formulář

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

David Grudl školí, je autorem PHP knihoven Nette Framework, databázové vrstvy dibi a formátovače HTML kódu Texy!.

Komentáře: 21

Přehled komentářů

Kajman Validace dle regexp
mike Re: Validace dle regexp
Aichi validace skupin
Mastodont Po sté to samé?
David Grudl Re: Po sté to samé?
danaketh Re: Po sté to samé?
Mastodont Re: Re: Po sté to samé?
David Grudl Re: Re: Re: Po sté to samé?
David Grudl Re: Re: Re: Re: Po sté to samé?
Martin Hassman Re: Re: Re: Re: Re: Po sté to samé?
Mastodont Re: Re: Re: Re: Po sté to samé?
David Grudl Re: Re: Re: Re: Re: Po sté to samé?
Roman Pištěk Re: Po sté to samé?
Mastodont Re: Re: Po sté to samé?
cckar newbie
David Grudl Re: newbie
Langi Re: Nette Framework: Neprůstřelné formuláře
Langi Re: Re: Nette Framework: Neprůstřelné formuláře
v6ak Re: Re: Re: Nette Framework: Neprůstřelné formuláře
Langi Re: Re: Re: Re: Nette Framework: Neprůstřelné formuláře
Jakub Vrána Re: Validace e-mailu
Zdroj: https://www.zdrojak.cz/?p=3022