Formulár vykreslený pomocou FormMacros pri metode GET nezohľadňuje query v action

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

Nette Framework 2.0-dev z 2011–06–24

Formulár vykreslený pomocou FormMacros {form name}...{/form} v prípade metódy GET nezohľadňuje query v action.

Napr. v prípade

$form->setAction('index.php?key=value');

je formulár odoslaný iba na index.php bez key=value.

DefaultFormRenderer pri metóde GET query v action vykresľuje pomocou HiddenField, vo FormMacros táto časť nie je.

Návrh na úpravu FormMacros (doplnené z DefaultFormRenderer::renderBegin())

public static function install(Latte\Parser$parser)
{
	...
	$me->addMacro('form', array($me, 'macroForm'), ...);
}

public function macroForm(MacroNode $node, $writer)
{
	return $writer->write('$form = $control[%node.word]; echo Nette\Latte\Macros\FormMacros::beginForm($form, %node.array)');
}

public static function beginForm($form, $attributes)
{
	if (strcasecmp($form->getMethod(), 'get') === 0) {
		$el = clone $form->getElementPrototype();
		$url = explode('?', (string) $el->action, 2);
		$el->action = $url[0];
		$s = '';
		if (isset($url[1])) {
			foreach (preg_split('#[;&]#', $url[1]) as $param) {
				$parts = explode('=', $param, 2);
				$name = urldecode($parts[0]);
				if (!isset($form[$name])) {
					$s .= Nette\Utils\Html::el('input', array('type' => 'hidden', 'name' => $name, 'value' => urldecode($parts[1])));
				}
			}
				$s = "\n\t" . Nette\Utils\Html::el('div')->setHtml($s);
		}
		return $el->addAttributes($attributes)->startTag() . $s;


	} else {
		return $form->getElementPrototype()->addAttributes($attributes)->startTag();
	}
}

Editoval dakota (25. 6. 2011 12:48)

Ondřej Mirtes
Člen | 1536
+
0
-

To je záležitost RFC, tudíž chování prohlížečů.

medvedobijec
Člen | 11
+
0
-

Ahoj, narazil jsem dnes na podobný problém s odesíláním GETového formuláře a příčina je stejná. U renderování formuláře s metodou GET osekne DefaultFormRenderer action a doplní hidden políčko – např <input type="hidden" name="do" value="myForm-submit" /> Jenomže to se v případě FormMacros neděje.

Mikulas Dite
Člen | 756
+
0
-

FormMacros nechtějí mít závislost na DefaultFormRenderer. Takhle chyba se bude ale ve stringu opravovat špatně. Přesouvat to do další funkce není vůbec nette-way.

Co kdyby to závislost mělo, ale nějakým setterem se dal DefaultFormRenderer nahradit za potomka? To by byl win-win, protože se form-macros zjednodušší a navíc se bude moc chování formů měnit jednou snadno přenositelnou třídou.

dakota
Člen | 148
+
0
-

Závislosť FormMacros na nejakom rendereri by možno malo výhodu aj pri opakujúcich sa veciach ako sú napr.:

  • pri povinných prvkoch doplnenie *, triedy class=„required“ a pod
  • doplnenie dvojbodky
{label title}Titulok:<span class="required-suffix" n:if="$form['title']->isRequired()">*</span>{/label}

by stačilo zapisať ako

{label title}Titulok{/label}

Správanie by sa dalo upraviť nastavením rendereru, príp. jeho nahradením.

DefaultFormRenderer je nato však dosť obsiahly. Možno by stačil nejaký zjednodušený renderer.

Editoval dakota (25. 6. 2011 20:59)

medvedobijec
Člen | 11
+
0
-

Tak jsem si jako workaround zkopíroval kód z DefaultFormRendereru a upravil makro následovně. Ale je to šílenost a chtělo by to asi řešit nějak koncepčně.

$me->addMacro('form', '
	$form = $control[%node.word];
	if (strcasecmp($form->getMethod(), \'get\') === 0) {
		$el = clone $form->getElementPrototype();
		$url = explode(\'?\', (string) $el->action, 2);
		$el->action = $url[0];
		$s = "";
		if (isset($url[1])) {
			foreach (preg_split(\'#[;&]#\', $url[1]) as $param) {
				$parts = explode(\'=\', $param, 2);
				$name = urldecode($parts[0]);
				if (!isset($form[$name])) {
					$s .= Nette\Utils\Html::el(\'input\', array(\'type\' => \'hidden\', \'name\' => $name, \'value\' => urldecode($parts[1])));
				}
			}
			$s = "\n\t" . Nette\Utils\Html::el(\'div\')->setHtml($s);
		}
		echo $el->startTag() . $s;
	} else {
		echo $form->getElementPrototype()->addAttributes(%node.array)->startTag();
	}',
	'?><div><?php
		foreach ($form->getComponents(TRUE, \'Nette\Forms\Controls\HiddenField\') as $_tmp) echo $_tmp->getControl();
		if (iterator_count($form->getComponents(TRUE, \'Nette\Forms\Controls\TextInput\')) < 2) echo "<!--[if IE]><input type=IEbug disabled style=\"display:none\"><![endif]-->";
	?></div>
	<?php echo $form->getElementPrototype()->endTag()');