Profíci, jak tvoříte vlastní formulářové komponenty?
- David Grudl
- Nette Core | 8227
Představte si, že chcete udělat formulářový prvek pro zadávání data, podobný jako používá Facebook, tedy s odděleným políčkem pro den, měsíc a rok (mohou to být selectboxy):
Api by mělo přijímat a vracet jako hodnotu objekt DateTime.
Jakým způsobem v současné verzi Nette podobný prvek navrhnete?
- Filip Procházka
- Moderator | 4668
Podědím BaseControl a napíšu metodu getControl tak, aby vytvořila 3 inputy (selecty). Potom setValue a getValue naučím pracovat s datetime.
Už tu třídu nepoužívám, ale pro představu cca takhle.
Editoval Filip Procházka (26. 6. 2013 23:19)
- Milo
- Nette Core | 1283
Podobné inputy řeším cca takto. Jen dědím z LatteBaseControl, abych mohl getControl() provádět v Latte.
class DateInput extends Nette\Forms\Controls\BaseControl
{
private $emptyValue = array('y' => '', 'm' => '', 'd' => '');
public function getControl()
{
$value = $this->getHtmlValue();
$d = Html::el('input')->name($this->name . '[d]')->value($value['d']);
$m = Html::el('input')->name($this->name . '[m]')->value($value['m']);
$y = Html::el('input')->name($this->name . '[y]')->value($value['y']);
return Html::el()->add($d)->add($m)->add($y);
}
public function setValue($value)
{
if (is_array($value)) {
$this->value = $value + $this->emptyValue;
} elseif ($value instanceof \DateTime) {
$this->value = array(
'y' => $value->format('Y'),
'm' => $value->format('m'),
'd' => $value->format('d'),
);
} else {
$this->value = NULL;
}
return $this;
}
protected function getHtmlValue()
{
if (is_array($this->value)) {
return $this->value;
}
return $this->emptyValue;
}
public function getValue()
{
$value = $this->getHtmlValue();
$value = \DateTime::createFromFormat('Y-m-d', "$value[y]-$value[m]-$value[d]");
if ($value === FALSE) {
return NULL;
}
return $value;
}
}
- hrach
- Člen | 1838
Na signálech Jan Tvrdík před více jak 3 lety zavedl abstraktní formulářovou komponentu, ktera implementuje standardní komponentové rozhraní.
Jednotlivé formulářové komponenty pak mohou mít interně kolik chcou komponent.
V rámci nextras jsem před měsíci udělal WIP, ještě není dodělané, vypadá to takto:
- form komponenta, která implemetuje Component
- v praxi:
- date range picker .php
- date range picker .latte
Je to neuvěřitelně mocný nástroj, asi nejsložitější komponentu
v tom máme takovou, který dokonce obsahuje popup. Komponenta saba o sobě
umí nastavovat přístupová oprávnění pro skupiny, etc, ala Facebook:
všechno žlutý je jedna formulářová komponenta
$form->addAuthUtil()
. Popup se zobrazí po vybrání položky
upřesnit v hlavnim inputu…
Editoval hrach (27. 6. 2013 8:26)
- enumag
- Člen | 2118
@Milo: To já taky, ale nejvíc jsem zvědavej jestli opraví to co mi ve formulářích chybí:
- praktická nemožnost přidávání vlastních validátorů včetně JS varianty
- signál validate pro live validaci callback validátorů (např. kontrola zda uživatel již existuje)
- možnost změny chybových zpráv automaticky přidaných pravidel (např. selectbox invalid value)
Editoval enumag (27. 6. 2013 13:14)
- Filip Procházka
- Moderator | 4668
<ot>Největší bolest formulářů je v současnosti pevně svázaný validátor :)</ot>
Editoval Filip Procházka (27. 6. 2013 12:47)
- David Grudl
- Nette Core | 8227
enumag: cože? Tohle je co? https://github.com/…alidator.php#L18. V té custom JS validaci si pak snadno můžeš třeba ověřit přes AJAX data.
Select invalidate message se změní v
Nette\Forms\Rules::$defaultMessages
. Navíc to není potřeba, ta
zpráva se uživateli nezobrazí, jde o zabránění hackingu.
Filip: Tam přece žádný pevně svázaný validátor není. Všechny validace jsou ve třídě Validators. Ve formulářích je pak jen minimální obálka nad nimi. Lze to řešit líp?
- David Matějka
- Moderator | 6445
@David Grudl: jednotlive validace oddelene jsou, ale
snadno konfigurovatelny validator (ci seznam pravidel) je jen u formularu, se
kterym je pevne svazany. nevim, jak to myslel Filip, ale mne by se libilo, aby
validator sel napsat oddelene a byl by aplikovatelny nejen na form, ale treba
jen na pole (napr. vstup z api), nedavno se to tu na foru i resilo, videl jsem
i nejaky funkcni reseni, ale mohlo by to byt primo v nette :)
treba takto:
$validator = new Validator();
$validator->addText('foo')->addRule(Validator::FILLED)->addRule(Validator::MIN_LENGTH, 'Minimalni delka je %d znaku', 5);
$validator->addBoolean('bar');
....
$form = new Form();
$form->addText('foo', 'Foo');
$form->addCheckbox('bar', 'Bar');
$form->setValidator($validator);
//nebo treba z API ziskam nejaka data, tak
$result = $validator->validate($data);
//a v result bude stav a pripadne seznam chyb
- Filip Procházka
- Moderator | 4668
@David Grudl: Formuláře je můžou využívat, ale měly by jít použít samostatně. Což teď jdou velice težko.
V ideálním případě bych měl nějak nadefinované validace (fluentem
nad nějakým rules objektem, annotacemi, …), přes validátor který tyto
definice bude mít načtené bych prohnal strukturu (formulář, entitu, pole,
…) a vypadl by mi výsledek (violations) který by obsahoval chybové zprávy
a ke kterému prvku patří ($violations[email] = "neobsahuje @"
) a
tyto pravidla by se aplikovaly na formulář (protože vím jméno prvku, můžu
chybu přiřadit ke správnému políčku a správně vykreslit).
// pseudokód
$form->onValidate[] = function ($form) use ($entity) {
$entity->setValues($form->values);
$validator = new Validator(new MetadataReader($entity));
$result = $validator->validate($entity);
$form->addErrors($result);
};
Co tím získám? Zcela jasné oddělení validátoru, možnost plně jej využít i v modelových třídách nad entitami, validovat json strukturu co přijde v API, …
Editoval Filip Procházka (28. 6. 2013 2:40)
- llook
- Člen | 407
Doteď jsem tohle dělal zhruba tak, že jsem si těch několik HTML inputů
definoval v getControl()
a jako name jsem jim dal
$this->htmlName . '["year"]'
apod. A potom překlad z array na
cílový objekt a zpět v getValue()/setValue()
.
Ale to řešení s controlem implementujícím IContainer se mi líbí víc.
- David Matějka
- Moderator | 6445
David neco planuje s formularema, rikal to na posobote, nechtel ale prozradit co :)
- enumag
- Člen | 2118
@David Grudl: Tak už jsem si vzpomněl co mi u vlastních validátorů tak zásadně chybí. Není možné přes config nastavit default message. Nebo aspoň ne pomocí NetteExtension. Když nad tím tak přemýšlím tak mne nenapadá jak to kamkoli do configu napsat (bez použití vlastní extension).
Editoval enumag (25. 7. 2013 19:51)
- enumag
- Člen | 2118
@Filip Procházka: Všimni si tohoto řádku z NetteExtension:
$initialize->addBody('Nette\Forms\Rules::$defaultMessages[Nette\Forms\Form::?] = ?;', array($name, $text));
Kvůli tomu Nette\Forms\Form::?
tohle nelze použít na žádný
validátor který není jako konstanta přímo v Nette\Forms\Form
.
Když si napíšu vlastní validátor na dejme tomu telefonní číslo tak ten
tam tu konstantu nemá a default msg přes config nenastavím aniž bych psal
své Extension.
- Milo
- Nette Core | 1283
@David Grudl Právě jsem shlédl video z 56. Poslední soboty kde jsi nechal nakouknout do formulářů ve 2.1 a je to super. U jedné aplikace potřebuji přepsat systém přidělování oprávnění a tam se to hodí perfektně.
- ViPEr*CZ*
- Člen | 817
Milo napsal(a):
@David Grudl Právě jsem shlédl video z 56. Poslední soboty kde jsi nechal nakouknout do formulářů ve 2.1 a je to super. U jedné aplikace potřebuji přepsat systém přidělování oprávnění a tam se to hodí perfektně.
+1