Kde plnit formulář defaultními hodnotami?

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
duke
Člen | 650
+
0
-

Kde je dle vašeho názoru nejlepší volat metodu setDefaults()?

Zdá se, že většina lidí to řeší přímo v továrničce, což ale znamená, že v případě zpracování formuláře se v některých případech (pokud tyto hodnoty nejsou použity ještě k jiným účelům) zbytečně ztrácí čas načítáním těchto hodnot (např z databáze), neboť v tomto případě je metoda setDefaults() stejně zahodí.

V té souvislosti mě napadlo, zda by nebylo dobré přidat formulářům callback pro načtení defaultních hodnot, který by se automaticky volal, až by to bylo třeba. Tj. před vyrenderováním a jen za předpokladu, že neprobíhá zpracování formuláře.

enumag
Člen | 2118
+
0
-

Osobně to volám v action*.

hAssassin
Člen | 293
+
0
-

Osobne se prikladnim to plnit v tovarnicce nebo v action. Action se provadi po odeslani stejne pred volanim callbacku, ale je fakt ze to nebude lazy.

A proc v tovarnicce? Ty data, at jsou jakkoliv slozita, jsou potreba vzdy, ikdyz budou hnedle prepsany. Co kdyby ti nekdo podstrcil neplatnou hodnotu selektu? Potom tam musis nastavit tu vychozi. Ale kde ji vezmes, pokud tam ty vychozi hodnoty nebudes nastavovat?

Jinak napad s tim callbackem neni spatny, ale pokud dava smysl to co jsem napsal vys (a me to smysl dava), pak je zbytecny… Co ty na to?

Jan Tvrdík
Nette guru | 2595
+
0
-

Osobně se přikláním k tomu dělat to až v render*.

duke
Člen | 650
+
0
-

Tak jsem si ujasnil, že toto není obecně vyřešený problém, a každý si to řeší po svém. Krom strohé odpovědi, kde to voláte, jsem očekával také i nějaké argumenty, proč tak a ne jinak, a vyjádření k nápadu ohledně callbacku. V tomto směru děkuji především hAssassinovi. Doufám, že přibudou i další reakce.

Jinak bych ještě doplnil původní otázku o pod-otázku, kde voláte setDefaults u formulářů, jež nejsou přímo v presenteru, ale hlouběji v hierarchii komponent.

hAssassin napsal:

Osobne se prikladnim to plnit v tovarnicce nebo v action. Action se provadi po odeslani stejne pred volanim callbacku, ale je fakt ze to nebude lazy.

Přesně tak. Pokud to bude v action nebo render metodě, nebude to lazy, což je škoda.

hAssassin napsal:

A proc v tovarnicce? Ta data, at jsou jakkoliv slozita, jsou potreba vzdy, i kdyz budou hnedle prepsana.

Někdy jsou opravdu ona data potřeba. Např. když chceme detekovat, že od posledního zobrazení někdo data pozměnil z vnějšku, a zabránit tak ztrátě dat, ale i v jiných případech. Nemyslím si ale, že z toho vyplývá, že je třeba načítat všechny hodnoty znovu vždy, jak tvrdíš. Nejde vždy jen o editaci nějakého záznamu, může jít i o jeho vytvoření, přičemž se do defaultních hodnot mohou předvyplnit data daná složitým výpočtem a je zbytečné tento výpočet opakovat při každém submitu formuláře (včetně submitů s chybami mimochodem), když bude jeho výsledek zahozen…

hAssassin napsal:

Co kdyby ti nekdo podstrcil neplatnou hodnotu selektu? Potom tam musis nastavit tu vychozi. Ale kde ji vezmes, pokud tam ty vychozi hodnoty nebudes nastavovat?

Dřív se toto dalo řešit validačním pravidlem, které v takovém případě označilo select jako nevalidní a callback onSuccess se v takovém případě tedy nezavolal. Nedávno bylo toto validační pravidlo přidáno do selektů automaticky, viz tento commit.

hAssassin napsal:

Jinak napad s tim callbackem neni spatny, ale pokud dava smysl to co jsem napsal vys (a me to smysl dava), pak je zbytecny… Co ty na to?

IMHO není zbytečný, protože umožňuje naprosto lazy řešení (tj. více lazy, než řešení skrz továrničku, neboť továrnička se může volat, i když se formulář nakonec vůbec nevykreslí).
Ale možná jsem přehlédl něco, co stojí řešení callbackem v cestě, a proto se Vás také ptám, co vy na to…

Editoval duke (17. 4. 2013 18:48)

David Grudl
Nette Core | 8282
+
0
-

Co může být více lazy než továrnička? Nevidím důvod ji nevyužít.

Jan Tvrdík
Nette guru | 2595
+
0
-

Přesně tak. Pokud to bude v action nebo render metodě, nebude to lazy, což je škoda.

V render* metodě to bude v podstatě lazy (nastaví se to při vykreslení, ale už ne při zpracování, kdy to není většinou potřeba).


Důvod, proč to radši dělám v render* metodě je, že ušetřím pár znaků. Srovnej následující dvě řešení.

public function renderEdit($id)
{
	$article = $this->model->load($id);
	if (!$article) $this->error();
	$this['editForm']->setDefaults($article);
}

protected function createComponentEditForm()
{
	$form = new UI\Form();
	...
	return $form;
}
private $article;

public function actionEdit($id)
{
	$this->article = $this->model->load($id);
	if (!$this->article) $this->error();
}

protected function createComponentEditForm()
{
	$form = new UI\Form();
	...
	$form->setDefaults($this->article);
	return $form;
}
duke
Člen | 650
+
0
-

David Grudl napsal:

Co může být více lazy než továrnička? Nevidím důvod ji nevyužít.

Více lazy je právě to řešení přes callback, který se volá, až když je to nezbytně nutné. Tj. např. callback navázaný na událost onBeforeRender. Již jsem to zdůvodnil ve svém prvním příspěvku. Jde o to, že plnit formulář daty je třeba pouze v případě, kdy formulář není odeslán. Plnit ho, i když probíhá submit, je kontraproduktivní, zejména pokud je operace získání výchozích dat náročná na prostředky (např. se musí načítat z databáze).

Další důvod proč nevyužít továrničku možná zná Patrik Votoček, jak lze usuzovat z jeho doporučení. Bohužel to nezdůvodnil.

Jan Tvrdík napsal:

V render* metodě to bude v podstatě lazy (nastaví se to při vykreslení, ale už ne při zpracování, kdy to není většinou potřeba).

Zvaž případ, kdy se formulář renderuje v šabloně podmíněně (např. podle práv uživatele editovat záznam). Pak jej voláním $this['editForm'] zbytečně vytváříš a následně plníš daty.

Jan Tvrdík napsal:

Důvod, proč to radši dělám v render* metodě je, že ušetřím pár znaků.

A jak to děláš u formulářů uvnitř komponent?

Editoval duke (19. 4. 2013 0:57)

Jan Tvrdík
Nette guru | 2595
+
0
-

Zvaž případ, kdy se formulář renderuje v šabloně podmíněně (např. podle práv uživatele editovat záznam). Pak jej voláním $this['editForm'] zbytečně vytváříš a následně plníš daty.

To je strašně vzácné, nepotřebuji to nijak řešit.

A jak to děláš u formulářů uvnitř komponent?

Tam je to jedno. Asi spíš v továrničce (zase ušetřím pár znaků).

Filip111
Člen | 244
+
0
-

Tohle už tedy neplatí jako best practise?
https://pla.nette.org/…cni-formular

David Grudl
Nette Core | 8282
+
0
-

Takhle:

protected function createComponentEditForm($name)
{
	$form = new UI\Form($this, $name);
	if (!$form->isSubmitted()) {
		$form->setDefaults(...);
	}
	return $form;
}

Jan Tvrdík napsal(a):

To je strašně vzácné, nepotřebuji to nijak řešit.

Pokud kešuješ část šablony s formulářem, tak se to hodí.

duke
Člen | 650
+
0
-

David Grudl napsal:

Takhle:

protected function createComponentEditForm($name)
{
	$form = new UI\Form($this, $name);
	if (!$form->isSubmitted()) {
		$form->setDefaults(...);
	}
	return $form;
}

Díky, toto řešení mě nenapadlo. Dodám, že v tomto případě je možné místo setDefaults volat přímo setValues, jak plyne z implementace metody setDefaults

Takže toto je teď oficiální best-practice pro vytváření formulářových komponent?

Ještě zde asi bude mírný nesoulad s touto featurou, kdy výše nastíněné řešení neumožní znovunastavení disabled inputů. Takže pokud někdo chce využívat tuto featuru, bude muset setDefaults (alespoň s hodnotami pro disabled inputy) volat i při submitu v případě chyby (nejlépe asi přes událost onError).

Editoval duke (23. 4. 2013 7:03)