Nacházíte se ve scénáři druhého screencast, pokud chcete můžete přejít na seznam scénářů jednotlivých screencastů.
Dotazy na tento scénář nebo na screencast o Nette piště prosím Tomikovi (autorovi tohoto textu) na tomik@jmx.cz.
Screencast – Formuláře – scénář
Informace o scénáři
- Název: Formuláře
- Délka: cca 10 minut
0. Úvodní znělka
1. Slide s informace o screencastu
3. Přestavení
Mluvené slovo + video hovořícího moderátora, který se představuje (to budu jako já :D).
„Dobrý den, vítám Vás u Nettecastu, tedy screencastu o Nette Frameworku.“
„V tomto screencastu si povíme, jak nám může Nette Framework ulehčit práci s formuláři.“
4. Požadavky
„A co budete pro práci s formuláři v Nette potřebovat? Stáhnuté Nette, které si vložíte do svého projektu – pokud nevíte jak na to, podívejte se na screencast o zprovoznění Nette – a základní znalosti o programování v PHP. Nic víc.“
5. Začínáme
„Proč vlastně Nette pro tvorbu formulářů využít? Odpověď je jednoduchá: i při tvorbě obyčejného formuláře o několika položkách je mnoho věcí, na které se nesmí zapomínat, a ruku na srdce, pokud takový formulář píšeme ‚z hlavy‘, pak pravděpodobně na spoustu takových věcí zapomínáme, nebo je prostě jen vědomě neřešíme. A právě proto Nette spousty takových věcí řeší za vás tak, abyste na ně nemuseli myslet.“
„Začneme samozřejmě tím, že si Nette do projektu přidáme, např. takto:“
require 'Nette\loader.php';
„Téměř veškeré možnosti, které Nette nabízí pro usnadnění práce s formuláři, v sobě skrývá třída Form. S její pomocí vytvoříme nový formulář:“
$form = new Form;
„Nyní přidáme nějaké položky. Budeme vytvářet registrační formulář a od uživatele budeme chtít znát jeho jméno a věk.“
$form->addText('name', 'Jméno:');
$form->addText('age', 'Věk:');
„Prvním parametrem je vždy název prvku, druhým je jeho popisek.“
„Nyní bychom chtěli vložit položku pohlaví. Víme, že pohlaví může být mužské nebo ženské – vytvoříme si tedy pole s těmito hodnotami:“
$sex = array(
'm' => 'muž',
'f' => 'žena',
);
$form->addRadioList('gender', 'Pohlaví:', $sex);
„Všimněte si, že u tohoto prvku přibyl třetí parametr, kterým je pole možností, kterých může nabývat – v tomto případě tedy pohlaví.“
„Dále bychom do formuláře chtěli vložit políčko pro e-mailovou adresu, heslo a tlačítko.“
$form->addText('email', 'E-mail:');
$form->addPassword('password', 'Heslo:');
$form->addSubmit('ok', 'Registrovat');
„Formulář je hotový, jednoduše jej zobrazíme.“
echo $form;
„Ještě než si prohlédneme výsledek v prohlížeči upozorním, že
skript by měl být uložen v kódování UTF. Jiné kódování je nutné
formuláři nastavit zavoláním metody setEncoding po jeho
vytvoření.“
„Nyní si tedy otevřeme prohlížeč…“
„Vidíme, že pomocí několika málo řádek se nám podařilo vytvořit skoro hotový formulář.“
6. Zpracování formuláře
„Buď lze nastavit, kam se formulář odešle pomocí metody
$form->setAction('zpracuj.php'); nebo lze využít zpracování
pomocí php souboru, který formulář vytvořil, k tomu využijeme
metody:“
// Přednastavíme některé hodnoty (je na uživateli, zda je změní)
$form->setDefaults(array(
'gender' => 'm' // Předpokládejme, že většina našich uživatelů budou muži :)
));
// Byl formulář odeslán a správně vyplněn?
if($form->isSubmitted() && $form->isValid()) {
echo '<h1>Formulář byl odeslán</h1>';
// Získáme hodnoty
$values = $form->getValues();
// Data vypíšeme (v normální aplikaci bychom je na tomto místě zpracovali)
Debug::dump($values);
// Skript ukončíme (v normální aplikaci bychom přesměrovali na jinou adresu, aby uživatel nemohl obnovením stránky data odeslat znovu
exit;
}
„Nebo můžete u formuláře definovat callbackovou funkci… Pokud nevíte, jak callbacky fungují a jak se používají, zkuste si na ně posvítit v API dokumentaci Nette třídy Object nebo přímo na php.net. Callback tedy nadefinujeme takto:“
$form->onSubmit[] = 'FormSubmitted';
„Taktová funkce dostane fomulář jako parametr, takže jej pak může zpracovat:“
function FormSubmitted($form)
{
$values = $form->getValues();
// Následuje zpracování dat...
/*Debug::dump($values);*/ print_r($values); // Ukáže nám, co jsme odeslali
// ?? Použít zde klasické print_r nebo Debug::dump() (to jsme zatím neprobrali)
}
„Tato funkce bude zavolána až v případě, že byl formulář odeslán
a všechna data jsou validní, není třeba tedy data kontrolovat pomocí
isValid().“
„V případě, že náš formulář by měl více tlačítek, je možné zpracovávací callback nastavit pro jednotlivá tlačítka..“
$form->addSubmit('ok', 'OK')->onClick[] = 'OkSubmitted';
$form->addSubmit('cancel', 'Cancel')->onClick[] = 'CancelSubmitted';
„S tím, že funkce pro zpracovávání nedostává jako parametr formulář, ale tlačítko, jakým byl odeslán… Takže je nutné toto:“
function OkSubmitted($button)
{
$form = $button->getForm();
$values = $form->getValues();
// Následuje zpracování dat...
/*Debug::dump($values);*/ print_r($values); // Ukáže nám, co jsme odeslali
}
6. Ještě dále, a ještě lépe!
„Takový formulář ovšem nemá žádnou validaci, a vlastně ani jinou přidanou hodnotu, kterou jsem sliboval. Pojďme si tedy ukázat, jak dosáhnout toho, že uživatel vloží do fomuláře opravdu to, co po něm chceme. Pojďme se podívat na možnosti validace fomulářů v Nette:“
„První položkou je políčko se jménem, to budeme požadovat. Přidáme
tedy validaci na prvek name.“
$form['name']->addRule(Form::FILLED, 'Zadejte jméno');
„První parametr říká, o jaké pravidlo se jedná; druhý pak specifikuje chybovou hlášku.“
„Vzhledem k tomu, že Nette\Form disponuje fluent rozhraním, je možné validaci definovat už při vytváření prvku, tedy takto:“
$form->addText('name', 'Jméno:')
->addRule(Form::FILLED, 'Zadejte jméno');
„Povinný prvek získá CSS třídu required – je tedy
možné si políčko nastylovat.“
„Pojďme se na to podívat v prohlížeči: Nette samo vygenerovalo potřebný JavaScript, takže když se nyní pokusíme odeslat nevyplněný formulář,“ – demonstrováno kliknutím na odesílací tlačítko – „vidíme, že jsme požádáni o vyplnění potřebného políčka a validace nám nedovolila formulář odeslat.“ „Zkusíme do formuláře zadat jako hodnotu mezeru. Odešleme… A nic. Zase se neodeslal, políčko bylo vyhodnoceno jako prázdné.“
„Tak si vypneme JavaScript…“ – řečeno s pocitem jak jsem na ně vyzrál
„…ale ani to nám není nic platné – opět jsme upozorněni na nutnost vyplnit políčko, tentokrát serverem. Nette se o všechny validace postaralo – stačilo k tomu definovat jedno pravidlo!“ – vykřičník značí patřičný WOW efekt
„Podívejme se na něco těžšího. U políčka s věkem budeme chtít, aby bylo povinné a jeho hodnota byla číslem v rozmezí 5 až 120 let.“
$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 %d do %d let', array(5, 120));
„Všimněte si, že v chybové hlášce, která se týká rozmezí, se uvádějí zástupné znaky namísto konkrétních čísel – ta se vezmou ze třetího parametru, čoz je pole s čísly určující interval rozsahu.“
„Dále budeme chtít přidat validaci na políčko s e-mailem.:“
$form->addText('email', 'E-mail:')
->addRule(Form::EMAIL, 'E-mailová adresa není platná');
„V takovémto případě ale bude e-mailová adresa požadována, může ale nastat situace, kdy ji nebudeme požadovat, ale budeme ji chtít validovat pouze v případě, že je zadána. Pro takové požadavky má Nette podmínky, jak na to?“
„Před definici pravidla prostě přidáme pomocí
addCondition podmínku, která musí platit, aby se aplikovalo
pravidlo.“
$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ý
„V tomto případě se vám na zpracování dostane buď validní mailová adresa, nebo prázdný řetězec.“
„Jestli se někdo z vás pokoušel registrovat na nějaký web z ciziny, jistě mi dáte za pravdu, že na některých klávesnicích najít zavináč je opravdu úkol hodný Esa Rimmera, jak tedy našim uživatelům, kteří nesedí u svého PC pomoci?“
„Můžeme u každého prvku nastavit tzv. prázdnou hodnotu. Co to znamená? Pojďme si to ukázat…“
$form->addText('email', 'E-mail:')
->setEmptyValue('@') // předvyplněna hodnota!
->addCondition(Form::FILLED) // podmínka: pokud je e-mail vyplněn
->addRule(Form::EMAIL, 'E-mailová adresa není platná'); // pak musí být platný
„Předcházející definici prvku jsem doplnil o
setEmptyValue('@'), to znamená, že tato hodnota bude v políčku
‚předvyplněna‘, ale pokud nedojde k její změně, je to bráno jako
prázdná hodnota a ke zpracování formuláře se dostane prázdný
řetězec.“
„Pokud se nyní na formulář podíváme, vidíme, že u políčka e-mail je předvyplněn @.“
„Doplníme ještě validaci políčka pro heslo:“
$form->addText('password', 'Heslo:')
->addRule(Form::FILLED, 'Zadejte heslo!');
„Nyní máme hotovou celou validaci formuláře, když si ji prohlédneme, můžeme vidět, že se nám jako uživateli opravdu nepodaří odeslal nějakou informaci, kterou daná položka neakceptuje…“
„Pokud se pokusím formulář odeslat se špatnými hodnotami, upozorní mě.“
„Pokud vše vyplním správně, ale e-mail nechám prázdný…“ – odeslání formuláře – „…vidíme, že neproběhla kontrola na správný tvar e-mailové adresy (protože prázdná hodnota by kontrolou neprošla), a ani předvyplněný zavináč se do výstupních dat nedostal.“
Nepřidat ještě 2 políčka na heslo, která se musí rovnat?
7. A co ochranu, tu používáte?
„Kdo z Vás používá ochranu proti podvržení falešného požadavku na fomulář – tzv. Cross-Site Request Forgery? Pokud jste o tomto útoku neslyšeli, pak vězte, že se jedná o poměrně nebezpečný způsob, jak provést akce, které uživatel nemusí schválit, může tedy takto útočník např. smazat položky, případně provést jiné administrátorské operace, má-li právě přihlášený uživatel admin práva.“
„Jak tomuto s Nette zabránit? Snadno!“
„Stačí po vytvoření formuláře přidat obranu a to takto:“
$form->addProtection('Vypršel ochranný časový limit, odešlete prosím formulář ještě jednou');
„A formulář je chráněný, formulář si sám generuje ochrané hashe a ty konkroluje, takže na útok, pokud se o něj někdo pokusí, přijde sám…“
8. Vykreslování
„Pokud se Vám nelíbí způsob, jakým se Nette formuláře vykreslují (ve výchozím nastavení do tabulky), pak si můžete toho chování velmi jednoduše změnit:“
„Nejprve si vezmeme vykreslovač – tzv. renderer formuláře:“
$renderer = $form->getRenderer();
„A tomu nyní můžeme nastavit, čím se mají jednotlivé prvky formuláře obalit:“
$renderer->wrappers['controls']['container'] = 'dl';
$renderer->wrappers['pair']['container'] = NULL;
$renderer->wrappers['label']['container'] = 'dt';
$renderer->wrappers['control']['container'] = 'dd';
„Že nevíte, co jednotlivé názvy znamenají? Na tomto přehledném obrázku…“
http://i.iinfo.cz/…formular.gif – ukážu obrázek
„… si můžete prohlédnou, jak jsou jednotlivé prvky formuláře rozděleny do skupin.“
„Mnou napsané nastavení…“ – přepnu zpět na nastavení
vykreslovače – „…tedy obalí celý formulář do definičního seznamu.
Dvojici popisek-prvek nechá neobalenou, ale samotný popisek obalí značkou
dt a samotný prvek značkou dd.“
„A vidíme, že se nám formulář vykreslil jinak…“ – ukazuje formulář v prohlížeči
„V případě, že by se Vám takovéhle změny nechtělo provádět při
každém použití formulářů, stačí si třídu Form podědit a
změnit způsob vykreslování jejímu potomkovi.“
9. Mnoho dalšího
„Nette Forms nabízí mnoho dalšího – lze pracovat se všemi HTML formulářovými prvky, lze validovat vlastními funkcemi. Stejně tak jako v celém Nette i jakoukoli část formulářů v Nette, pokud vám nevyhovuje, je možné si ji podědit a změnit k obrazu svému.“
„A pokud Vám chybí něco v základních Nette Forms, pak jsou další prvky v Nette Extras repozitáři…“
- Ukážu DatePicker,
- FileMultiUploader,
- Captchu,
- nebo třeba Live validaci.
(v nejbližší době plánuji uvolnit další 3 formControly na práci s čísly) Honza Kuchař
10. Příklady
„V distribuci se nachází spousta příkladů práce s formuláři, doporučuju si je všechny prohlédnout a inspirovat se.“
11. Závěr
„Nyní už víte jak pracovat s Nette formuláři, a že vám Nette pomůže s jejich tvorbou i zpracováním.“
„Pokud Vás zajímají všechny možnost Nette formulářů, doporučuji si
projít API na adrese http://api.nette.org – zde klikněte na
Nette\Form…“
(Odkazovat do API nebo do průvodce programátora?) Honza Kuchař
„Pokud Vám není něco jasné, obraťte se na fórum, tam se nachází spousta lidí, kteří vám rádi pomohou.“
„Děkuji za pozornost!“
Dotazy na tento scénář nebo na screencast o Nette piště prosím Tomikovi (autorovi tohoto textu) na tomik@jmx.cz.