Form: setDefaults() a nezpracování požadavku

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

Pokud použiju setDefaults() před přidáním všech formulářových polí, veškerá další pole za zavoláním setDefaults() jsou ignorována při zpracování požadavku:

$form = new Form;

$form->addText('foo', 'foo:');
$form->setDefaults(array('foo' => 'bar'));

$form->addText('baz', 'baz:');

$form->addSubmit('ok', 'OK');
$form->onSubmit[] = '_submit';

function _submit(Form $form)
{
    var_dump($form->getValues(), $_POST);
}

$form->isSubmitted();

echo $form;

V tomto případě se ani _submit() nezavolá. Pokud jde o AppForm, tak tam se zpracovávací funkce zavolá (protože se obsluhuje pomocí signálů?), ale všechna další přidaná pole po setDefaults() jsou ignorována.

Revize 476, PHP 5.2.10, Arch Linux, Apache/2.2.11

Editoval jakubkulhan (8. 8. 2009 13:46)

vlki
Člen | 218
+
0
-

Vzhledem k tomu, že výchozí hodnoty by se do formuláře měly zapsat jedině v případě, že není formulář odeslaný, tak se to musí zjistit. Dojde tedy k zpracování HttpRequestu. A ten se musí zpracovat jen jedinkrát.

Při volání setDefaults se tedy HttpRequest zpracuje a zbytek definice formuláře je při tomto zpracování ignorován.

Tím pádem se musí setDefaults nastavovat až po kompletní definici formuláře.

Nechápu, jak to ale může fungovat u AppForm…?

jakubkulhan
Člen | 55
+
0
-

vlki napsal(a):

Vzhledem k tomu, že výchozí hodnoty by se do formuláře měly zapsat jedině v případě, že není formulář odeslaný, tak se to musí zjistit.

Mně naopak přijde logické, že – hlavně tedy při použití s MVC s továrničkou v presenteru – si formulář naplním výchozími hodnotami při vytváření (tj. v továrničce) bez toho, abych ověřoval, jestli byl, či nebyl odeslán, protože o zpracování odeslání formuláře se stará presenter ve fázi Interaction.

Dojde tedy k zpracování HttpRequestu. A ten se musí zpracovat jen jedinkrát.

Souhlas. Ale jak souvisí zpracování formuláře s jeho naplněním výchozími hodnotami? Když vytvářím SelectBox, říkám, co může obsahovat – práce s hodnotami –, tak proč nemohu rovnou říct, jaká hodnota má být výchozí – taky jako v předchozím případě; práce s hodnotami, nebo ne?

Možný patch:

--- Form.php	(revision 476)
+++ Form.php	(working copy)
@@ -388,11 +388,12 @@

 	/**
 	 * Tells if the form was submitted.
+	 * @param bool process HTTP request?
 	 * @return ISubmitterControl|FALSE  submittor control
 	 */
-	public function isSubmitted()
+	public function isSubmitted($process = TRUE)
 	{
-		if ($this->submittedBy === NULL) {
+		if ($this->submittedBy === NULL && $process) {
 			$this->processHttpRequest();
 		}

@@ -491,7 +492,7 @@
 	 */
 	public function setDefaults($values, $erase = FALSE)
 	{
-		if (!$this->isSubmitted()) {
+		if (!$this->isSubmitted(FALSE)) {
 			$this->setValues($values, $erase);
 		}
 	}

(Poznámka: Proč jsou ksakru tabulátory převáděny na mezery?)

Pokud člověk před nastavováním výchozích hodnot ověřuje, jestli byl formulář odeslán pomocí isSubmitted(), nemělo by ho to nijak ovlivnit. Jestliže je takový blázen jako já a nedělá to, tak tenhle patch by mu měl přinést klidné spaní :-) Ale nevím, jak moc věcí závisí na tom, že vedlejším efektem volání setDefaults() je zpracování formuláře.

Ondřej Mirtes
Člen | 1536
+
0
-

V továrničce nic kontrolovat nemusíš. Bez problému to tam funguje, stačí, když setDefaults provádíš až po přidání všech prvků formuláře.

protected function createComponentForm() {
	$form = new AppForm($this, 'form'); //připojení ke controlu již tady, setDefaults to vyžaduje
	$form->addText('text', 'Text');
	//... další pole

	$form->setDefaults(array(
		'text' => 'Defaultní text',
	));

	$form->addSubmit('okSubmit', 'Odeslat');

	$form->onSubmit[] = array($this, 'formSubmit');

	//return $form; //již připojeno
}
jakubkulhan
Člen | 55
+
0
-

LastHunter napsal(a):

V továrničce nic kontrolovat nemusíš. Bez problému to tam funguje, stačí, když setDefaults provádíš až po přidání všech prvků formuláře.

Ano, já vím. Asi jsem to měl dát jasněji najevo, ale mně tu nejde o to, jak to vyřešit jinak. V podtitulku tohoto fóra je mimo jiné „Chcete nahlásit chybu?“ – a jelikož Issues na GoogleCode nejeví známky života, hlasím tedy věc, co považuji za chybu, tady.

PetrP
Člen | 587
+
0
-

Nemyslím si že je chyba že musíš setDefaults volat po přidání všech prvků (má to svojí logiku). Spíš by přidání prvku do formuláře který už má zpracovaný http požadavek mělo vyhodit výjimku.

Asi přidat do FormControl::attached() něco jako

protected function attached(FormContainer $formContainer)
{
	if ($formContainer->getForm() && $formContainer->getForm()->isPopulated()) {
		throw new ...Exception...
	}
}
jakubkulhan
Člen | 55
+
0
-

PetrP napsal(a):

Nemyslím si že je chyba že musíš setDefaults volat po přidání všech prvků (má to svojí logiku).

Stejně tak svoji logiku má volat setDefaults() třebas u každého pole – definici jednoho pole (do definice podle mě patří i výchozí hodnota) nechci mít roztahanou po celé továrničce (nebo ještě dokonce někde jinde), chci mít všechno u sebe.

A ještě když jsme u těch továrniček, tak pokud mám nějakou základní, která připraví pole, která jsou pro více formulářů společná, tak mi nepřijde zrovna moc dobré, abych je plnil v každé konkrétní továrničce zvlášť – DRY!

Spíš by přidání prvku do formuláře který už má zpracovaný http požadavek mělo vyhodit výjimku.

Ano, to rozhodně.

Ale pořád nevidím důvod, proč by setDefaults() mělo vyvolat zpracování požadavku? Až se požadavek zpracuje, výchozí data se přepíšou těmi z požadavku a přepsat pomocí setDefaults() už nepůjdou.

David Grudl
Nette Core | 8227
+
0
-

Ono to má svoji logiku – ale taky se mi to už dlouhodobě nelíbí. Snažím se s tím (už dlouhodobě) něco udělat ;)

David Grudl
Nette Core | 8227
+
0
-

Tak už se to povedlo ;) https://forum.nette.org/…te-formularu