Form validacia na zaklade ineho prvku a predavanie error hlasky
- westrem
- Člen | 398
Ahojte,
pre mnohych z Vas to asi nebude nic svetaborne ani nove, ale nedavno som
potreboval
- zviazat validaciu jedneho formularoveho prvku na hodnotu druheho
- mat moznost menit error hlasku pri nesplnenej validacii za behu
Samozrejme moje prve kroky smerovali na forum, kde sa to uz na par miestach riesilo, no thready vzdy koncili hlaskami typu, ze to Nette zatial nevie (mozno som len blbo hladal ale skutocne som nenasiel riesenie).
Kedze sa pod kapotu Nette pozeram stale a denne nezmieril som sa s tymto zaverom a isiel som si vyskusat moju teoriu (ze to ide) v praxi.
Vysledok
- zviazanie validacie na iny formularovy prvok
// pri tvorbe formularu
$form->addText('field1', 'Field 1');
$form->addText('field2', 'Field 2')
->addRule('myValidator', 'Error message', $form['field1']);
// vlastny validator
function myValidator($control1, $control2)
{
$val1 = $control1->getValue();
$val2 = $control2->getValue();
// nejaka validacia
// ..
return $isOk; // treba vratit bool hodnotu ci je hodnota v poriadku alebo nie
}
Pomerne intuitivne vsak? Vela ludi malo tendenciu robit nasledovnu chybu:
$form->addText('field2', 'Field 2')
->addRule('myValidator', 'Error message', $form['field1']->getValue());
co je samozrejme zle, pretoze v tomto momente sa formular len vytvara a do callback-u pre validaciu pravidiel sa teda nedostane nic alebo empty value.
V konecnom dosledku je priklad podobneho typu uvedeny aj vo formularovych
examples v distribucii ale je to dost zasite a najme tam je to ukazane na
Form::EQUAL (ktore ak sa nemylim je ako jedine robene tak, ze vie narabat aj
s predanymi IFormControl
implementatormi) – cim clovek moze
nadobudnut pocit, ze je to robene interne v Nette a vlastny validator nie
je mozny.
- moznost menit Error hlasku za behu
Tak toto je uz vec, ktoru som nenasiel fakt nikde a pritom si myslim, ze by Nette mohlo nieco take podporovat. Majme nasledovny priklad:
Mame entity zlavovy kupon, ktory moze stratit platnost 3 sposobmi:
- admin aplikacie ho rucne zakaze
- vyexpiruje doba pouzitia
- kupon uz bol pouzity dovoleny pocet krat
Pri vyplnani napr. objednavky poskytujeme ludom moznost ziskat zlavu zadanym
zlavoveho kuponu. Samozrejme kedze nechceme aby vznikali nedorozumenia tak
chceme platnost kuponu osetrit este pred potvrdenim objednavky – chceme
zvalidovat zadanu hodnotu v textovom poli. Mozno vas napadne, nasadit tri rozne
addRule
pravidla, pre kazdy pripad zvlast lenze to by znamenalo
minimalne 3 dotazy na DB (v kazdom validatore musime ziskat entitu z DB).
Zaroven to tak trochu dekompozicuje navrh aplikacie, kedze podla mna toto
semanticky patri pod jednu funkciu napr isVoucherValid($id)
, ktora
by sa mala postarat o zistenie ci je zlavovy kupon platny (nezavisle na
podmienkach invalidacie).
Zaroven kedze vsak chceme byt uzivatelsky privetivy, chceme im poskytnut adekvatny error message ako len „neplatny kupon“ (preco by mal byt neplatny, ked som ho nasiel napr. v casopise?)
Riesenie je sice tak torchu obklukou ale kedze validacne pravidla v Nette su napisane dost nauzko neviem o ziadnom inom, bez zasahu do FW.
1. Vytvorime si dummy Value object
final class ValueObject extends Object
{
private $value;
// samozrejme gettery a settery
// ..
// nasledne magia
public function __toString()
{
return (string) $this->value;
}
}
2. Defincia formularoveho prvku
$val = new ValueObject();
$form->addText('voucher', 'Zlavovy kupon')
->addRule('MyVoucherValidation', '%s', $val);
3. Validacia
function MyVoucherValidation($control, $val)
{
// predpokladam, ze na pracu s DB mame nejaky model
$model = new VoucherModel();
try {
// metoda isVoucherValid vyhadzuje vynimku s dovodom neplatnosti ako message
$model->isVoucherValid($control->getValue());
}
catch (VoucherException $e) {
$val->setValue($e->getMessage());
return FALSE;
}
return TRUE;
}
Tymto sposbom mozeme menit dovod error hlasky podla toho aky pripad
nevalidnosti nastal, pretoze do $val
sa ulozi spravna hodnota a ta
sa pri vypise error hlasky zobrazi (vdaka __toString()
metode).
Ako vravim, nie je to az tak svetaborne ale verim, ze niektorym ludom to moze pomoct :).