Zachycení exception vyhozené z loadHttpData

hlupec
Backer | 7
+
-1
-

Ahoj,

řeším problém, kdy chci ve formulářovém prvku v metodě setValue vyhodit exception při nevalidní hodnotě (po odeslání formuláře). Zaboha ale nemůžu přijít na to, kde takovou výjmku odchytit. V podstatě stejný případ se musí řešit pokud u nějakého potomka ChoiceControl chci mit enabled „checkDefaultValue“ – když je tam nějaká nepovolená hodnota, vyhodí se výjmka … kde jí chytnu? Třeba abych jí mohla přidělit formuláři pomocí addError?

Mám pocit, že mi uniká nějaká banalita:D

David Grudl
Nette Core | 7769
+
0
-

Jak s tím souvisí loadHttpData?

uživatel-p
Člen | 553
+
-2
-

Prď na ověřování v setValue. Ověř validitu pomocí validačních funkcí, které vrátí bool.

Editoval Polki (1. 11. 2021 19:23)

uživatel-p
Člen | 553
+
-1
-

Všichni ti géniové, co dávají mínusy by měly radši dávat řešení.
Ok řešení je to co jsem psal a tedy

public function __construct(string $label = null)
{
	parent::__construct($label);
	$this->addRule([self::class, 'validateMethod'], 'Wrong value');
}

public static function validateMethod(): bool
{
	// some logic
	return $result;
}

Díky čemuž nemusí nikde vyhazovat výjimky a validita dat se ověřuje opravdu až ve validaci a nad formulářem už se jím chtěná ‚addError‘ zavolá sama automaticky. Stejně tak daný validátor se dá použít i jinde než jen v daném formuláři, jelikož je to funkce, kterou můžeme volat odevšad a jelikož je statická, tak ji dokáže Nette spárovat s JS, takže máme i validaci na straně klienta. Za mě je toto řešení víc ok, než nějak modifikovat funkci onValidate a trápit se s tím co kde mám jak odchytit někde z HTTP requestu, nebo nastavování apod. Tohle udělá všechnu práci čistě, rychle a tehdy, kdy je potřeba. Samo Nette to takovým způsobem dělá například pro validaci E-mailu, Integeru apod. Nechápu tedy, co je na tom špatně pokud tedy podle vás géniů není špatně i samo Nette.

Jestli máte lepší řešení není problém, ale dávat palce bez vysvětlení, nebo navedení jak to je dobře můžou akorát lidi, co tomu sami nerozumí, nebo jen chtějí být cool.

Editoval Polki (1. 11. 2021 19:43)

hlupec
Backer | 7
+
0
-

David Grudl napsal(a):

Jak s tím souvisí loadHttpData?

Jde o metodu setValue, ktera se vola z metody loadHttpData – zminila jsem to jen proto, aby bylo jasne kde se ta metoda vola (ze jde o nacitani z POSTu).

hlupec
Backer | 7
+
0
-

Polki napsal(a):

Prď na ověřování v setValue. Ověř validitu pomocí validačních funkcí, které vrátí bool.

Jasne, ale na to se neptam ;)

hlupec
Backer | 7
+
0
-

Polki napsal(a):

Všichni ti géniové, co dávají mínusy by měly radši dávat řešení.
Ok řešení je to co jsem psal a tedy

Diky moc. Ja tuhle moznost validace samozrejme znam, ale zeptam se tedy jinak: zapomente na ten muj pripad a zamerte se na tu vyjmku, kterou vyhazuje metoda setValue u inputu dedenych z ChoiceControl. Pokud se nastavuje hodnota ktera neexistuje v poli moznosti, vyhodi se vyjmka – protoze nevim, kde ji chytit, tak by to vzdy koncilo server errorem. To prece nemohl byt zamer ne? (btw ted to resim tak, ze si u vsech techto inputu nastavuju checkDefaultValue(false) :))

Milo
Nette Core | 1255
+
+2
-

@hlupec To je správně, že tu výjimku nezachytíš a sletí aplikace. Někdo se totiž snaží procpat do formuláře data, která nedávají smysl.

David Grudl
Nette Core | 7769
+
+1
-

hlupec napsal(a):

Jak s tím souvisí loadHttpData?

Jde o metodu setValue, ktera se vola z metody loadHttpData – zminila jsem to jen proto, aby bylo jasne kde se ta metoda vola (ze jde o nacitani z POSTu).

Tak pokud setValue vyhazuje výjimku a loadHttpData volá setValue, tak by tu výjimku mělo zachycovat loadHttpData, ne?

hlupec napsal(a):

: zapomente na ten muj pripad a zamerte se na tu vyjmku, kterou vyhazuje metoda setValue u inputu dedenych z ChoiceControl.

ChoiceControl ale nevolá v loadHttpData metodu setValue

uživatel-p
Člen | 553
+
+3
-

hlupec napsal(a):

Diky moc. Ja tuhle moznost validace samozrejme znam, ale zeptam se tedy jinak: zapomente na ten muj pripad a zamerte se na tu vyjmku, kterou vyhazuje metoda setValue u inputu dedenych z ChoiceControl. Pokud se nastavuje hodnota ktera neexistuje v poli moznosti, vyhodi se vyjmka – protoze nevim, kde ji chytit, tak by to vzdy koncilo server errorem. To prece nemohl byt zamer ne? (btw ted to resim tak, ze si u vsech techto inputu nastavuju checkDefaultValue(false) :))

Pokud nejde o validaci dat jako takových, ale o vychozí chování Nette, tak to se chová tak jak má. Například když se ty snažíš jako výchozí hodnotu něco, co není v možnostech ChoiceControlu, tak to správně odfiltruje a vyhodí Error 500, jelikož jsi udělala chybu ty na straně serveru, jelikož se snažíš poslat nevalidní data.
Pokud ale pošle uživatel tvého formu nesmyslný vstup, tak se stane to, že tento nesmyslný vstup je odfiltrován pryč a jako hodnota se nastaví null viz funkce getValue a tedy projde i onSuccess s kódem 200OK.

Pokud ti nevalidní data z formuláře po odeslání vyhazují 500, tak je chyba na tvé straně v implementaci a tedy je třeba zjistit, proč to chybu vyhazuje, protože Nette na tom podíl nemá.

hlupec
Backer | 7
+
0
-

Nevim jestli by aplikace mela spadnout. Priklad: v administraci produktu mam select pro vyber kategorii – admin si vybere kategorii XYZ, jenze mezi tim, kdy nacetl formular a tim kdy ho odeslal, jiny admin kategorii XYZ smazal. Pak se prvnimu adminu vyhodi server error – podle me by se to melo nejak dat zachytit.

Ale ok, vysledek diskuze mi staci – zachytit to nelze → musim se vydat jinou cestou. Diky vsem.

Edit: jeste koukam do toho ChoiceControl – je pravda ze tam se metoda setValue v loadHttpData nevola (i kdyz jinde jo), takze by se to melo zachytavat asi v metode createComponentXyzForm.

Editoval hlupec (2. 11. 2021 5:22)

uživatel-p
Člen | 553
+
0
-

V tom případě co ty popisuješ nikdy ChoiceControl error nevyhodí. Jak jsem psal nesmyslna hodnota se odfiltruje pryč a vse probehne v pohodě s kodem 200

Milo
Nette Core | 1255
+
+3
-

@hlupec Pokud by aplikace nespadla a běžela dál, došlo by nevědomky ke ztrátě informace. Tím, že jako programátor nastavíš checkDefaultValue(false) už tak nějak počítáš s tím, že se ti tam může dostat nevalidní hodnota a ta se zahodí.

Rozumím, že ve tvém případě je to pouze komplikace, ale ta se dá snadno vyřešit. Pro výběr kategorie si můžeš udělat vlastní form control. Zhruba:

final class CategorySelect extends SelectBox
{
	public function setValue($value)
	{
		try {
			parent::setValue($value);
		} catch (Nette\InvalidArgumentException) {
			parent::setValue(null);
			$this->addError("Kategorie '$value' není k dispozici.");
		}
	}
}

nebo obecně zhruba:

final class SafeSelectBox extends SelectBox
{
	public function __construct(private Closure $onInvalidValue, $label = null, array $items = null)
	{
		parent::__construct($label, $items);
	}


	public function setValue($value)
	{
		try {
			parent::setValue($value);
		} catch (Nette\InvalidArgumentException $e) {
			parent::setValue(null);
			($this->onInvalidValue)($this, $value, $e);
		}
	}
}