Form validacia na zaklade ineho prvku a predavanie error hlasky

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

Ahojte,
pre mnohych z Vas to asi nebude nic svetaborne ani nove, ale nedavno som potreboval

  1. zviazat validaciu jedneho formularoveho prvku na hodnotu druheho
  2. mat moznost menit error hlasku pri nesplnenej validacii za behu

Samozrejme moje prve kroky smerovali na forum, kde sa to uz na par miestach riesilo, no thready vzdy koncili hlaskami typu, ze to Nette zatial nevie (mozno som len blbo hladal ale skutocne som nenasiel riesenie).

Kedze sa pod kapotu Nette pozeram stale a denne nezmieril som sa s tymto zaverom a isiel som si vyskusat moju teoriu (ze to ide) v praxi.

Vysledok

  1. zviazanie validacie na iny formularovy prvok
// pri tvorbe formularu
$form->addText('field1', 'Field 1');
$form->addText('field2', 'Field 2')
	->addRule('myValidator', 'Error message', $form['field1']);

// vlastny validator
function myValidator($control1, $control2)
{
	$val1 = $control1->getValue();
	$val2 = $control2->getValue();
	// nejaka validacia
	// ..
	return $isOk; // treba vratit bool hodnotu ci je hodnota v poriadku alebo nie
}

Pomerne intuitivne vsak? Vela ludi malo tendenciu robit nasledovnu chybu:

$form->addText('field2', 'Field 2')
	->addRule('myValidator', 'Error message', $form['field1']->getValue());

co je samozrejme zle, pretoze v tomto momente sa formular len vytvara a do callback-u pre validaciu pravidiel sa teda nedostane nic alebo empty value.

V konecnom dosledku je priklad podobneho typu uvedeny aj vo formularovych examples v distribucii ale je to dost zasite a najme tam je to ukazane na Form::EQUAL (ktore ak sa nemylim je ako jedine robene tak, ze vie narabat aj s predanymi IFormControl implementatormi) – cim clovek moze nadobudnut pocit, ze je to robene interne v Nette a vlastny validator nie je mozny.

  1. moznost menit Error hlasku za behu

Tak toto je uz vec, ktoru som nenasiel fakt nikde a pritom si myslim, ze by Nette mohlo nieco take podporovat. Majme nasledovny priklad:

Mame entity zlavovy kupon, ktory moze stratit platnost 3 sposobmi:

  • admin aplikacie ho rucne zakaze
  • vyexpiruje doba pouzitia
  • kupon uz bol pouzity dovoleny pocet krat

Pri vyplnani napr. objednavky poskytujeme ludom moznost ziskat zlavu zadanym zlavoveho kuponu. Samozrejme kedze nechceme aby vznikali nedorozumenia tak chceme platnost kuponu osetrit este pred potvrdenim objednavky – chceme zvalidovat zadanu hodnotu v textovom poli. Mozno vas napadne, nasadit tri rozne addRule pravidla, pre kazdy pripad zvlast lenze to by znamenalo minimalne 3 dotazy na DB (v kazdom validatore musime ziskat entitu z DB). Zaroven to tak trochu dekompozicuje navrh aplikacie, kedze podla mna toto semanticky patri pod jednu funkciu napr isVoucherValid($id), ktora by sa mala postarat o zistenie ci je zlavovy kupon platny (nezavisle na podmienkach invalidacie).

Zaroven kedze vsak chceme byt uzivatelsky privetivy, chceme im poskytnut adekvatny error message ako len „neplatny kupon“ (preco by mal byt neplatny, ked som ho nasiel napr. v casopise?)

Riesenie je sice tak torchu obklukou ale kedze validacne pravidla v Nette su napisane dost nauzko neviem o ziadnom inom, bez zasahu do FW.

1. Vytvorime si dummy Value object

final class ValueObject extends Object
{
	private $value;

	// samozrejme gettery a settery
	// ..

	// nasledne magia
	public function __toString()
	{
		return (string) $this->value;
	}
}

2. Defincia formularoveho prvku

$val = new ValueObject();
$form->addText('voucher', 'Zlavovy kupon')
	->addRule('MyVoucherValidation', '%s', $val);

3. Validacia

function MyVoucherValidation($control, $val)
{
	// predpokladam, ze na pracu s DB mame nejaky model
	$model = new VoucherModel();
	try {
		// metoda isVoucherValid vyhadzuje vynimku s dovodom neplatnosti ako message
		$model->isVoucherValid($control->getValue());
	}
	catch (VoucherException $e) {
		$val->setValue($e->getMessage());
		return FALSE;
	}
	return TRUE;
}

Tymto sposbom mozeme menit dovod error hlasky podla toho aky pripad nevalidnosti nastal, pretoze do $val sa ulozi spravna hodnota a ta sa pri vypise error hlasky zobrazi (vdaka __toString() metode).

Ako vravim, nie je to az tak svetaborne ale verim, ze niektorym ludom to moze pomoct :).