Eventy formuláře – matoucí předání parametrů
- m.brecher
- Generous Backer | 871
Ahoj,
Zkoušel jsem různé varianty zpracování odeslaného formuláře a narazil na „matoucí“ způsob předání parametrů do callbacku eventu formuláře. Mám nainstalované PHP 8.1, nette/forms 3.1.7 a nette/application 3.1.7.
Odesílací tlačítko
V ovladači onClick[] si můžeme vyžádat typehintem předání odesílacího SubmitButton $submitter. Přitom event onClick[] se ani jinak navěsit nedá než na konkrétní tlačítko formuláře:
$form->addSubmit('createButton', 'Uložit')->onClick[] = $this->createButtonClick(...);
Pokud navěsíme na každé tlačítko jemu odpovídající ovladač, tak obvykle není v ovladači onClick[] potřeba $submitter řešit. Ale hodit se to může.
U ovladače onSubmit[] ale překvapivě předání SubmitButton $submitter k dispozici není, přitom právě zde by se tento parametr hodil více ;) Představme si např. formulář s třemi odesílacími tlačítky createButton v módu nový záznam, updateButton a deleteButton v módu editace záznamu. Můžeme celý formulář s tlačítky postavit ve Factory bez použití navěšování ->onClick[] a v presenteru provést jednoduchou distribuci obsluhy podle parametru $submitter:
// ukázka jak by se hodilo velmi mít v onSuccess[] parametr $submitter
public function createComponentMyForm(): Form
{
$form = $this->myFormFactory->create();
$form->onSuccess[] = fn(SubmitButton $submitter, ArrayHash $values) => match($submitter->name){
'createButton' => $this->createFormSuccess($values),
'updateButton' => $this->updateFormSuccess($values),
'deleteButton' => $this->deleteFormSuccess($values),
default => throw new AppException('Unhandled submitter name.'),
};
return $form;
}
Mix předání parametrů podle typu a podle pozice
Podle dokumentace:
https://doc.nette.org/…in-presenter#…
https://doc.nette.org/…in-presenter#…
i podle testování lze parametry do ovladačů onClick[], onSuccess[] předat takto:
první parametr Form|SubmitButton ⇒ předá buďto $form nebo $submitter
(onSuccess[] $submitter ne)
druhý parametr ArrayHash|array|FormData ⇒ předá $values ve vyžádaném
formátu
Pozor, parametr $values je na druhém místě, ale může být předán i na prvním místě.
V zásadě to není vůbec navrženo špatně – komfortně si vybereme typehintem co potřebujeme, jenom si musíme pamatovat, že je třeba dodržet pořadí parametrů + že není v onSuccess možné předat $submitter. Ale některé aspekty matou, jsou to tyto:
- předává se podle typu Form, SubmitButton, ArrayHash, na první pozici může být cokoliv, připomíná to předávání služeb DI konstruktorem, kde na pořadí vůbec nezáleží
- když máme jako první parametr Form funguje to i po přidání ArrayHash na druhou pozici, obráceně ne – musíme pořadí prohodit
- v onSuccess[] nelze parametr SubmitButton předat vůbec, což je nelogické
- datová třída pro data formuláře nemá předepsaný interface, který by se hodil, aby v tom měl člověk i Nette pořádek, takhle se může stát, že když omylem na druhé pozici člověk napíše Form $form, obdrží v proměnné prázdnou instanci Form, což se mě také v některých případech stalo.
Návrh:
- předávat parametry Form, SubmitButton, ArrayHash|array|FormData VŠECHNY do obou ovladačů onClick[] i onSuccess[] nezávisle na pozici, ale výhradně podle typehintu
- požadovat, aby datová třída formuláře povinně implementovala nějaký v Nette vestavěný interface (např. Nette\Application\UI\Forms\Formdata), podle kterého by Nette mohlo jednoznačně rozhodnout, zda je to třída, kterou je očekáváno předat, v kódu aplikace to udělá pořádek, není to práce navíc
Chápu, že situaci komplikuje zpětná kompatibilita – někdo možná nepoužívá typování. Zde by bylo vhodné ponechat pořadí parametrů. Při kombinaci jeden parametr otypovaný, druhý ne ponechat pořadí parametrů, nebo vyhodit výjimku a požadovat parametry buďto typované všechny nebo žádný.
Návrh je v souladu s moderními trendy v PHP a frameworcích směřujícími k pohodlnější syntaxi a využívání typů. Např. pojmenované parametry PHP 8.0 přinesly to pohodlí, že řešíme jenom název a nikoliv pozici parametru.
Editoval m.brecher (16. 10. 2022 1:35)