ErrorPresenter vs persistentní parametry

26. 6. 2015

Aplikace je lokalizovaná a Nette nám persistentní parameter (v basePresenteru) $locale hezky pži každém requestu automaticky naplňuje. To je fajn, máme ho všude k dispozici. Po nějaké době chceme lokalizovat i chybové stránky. Otevřeme si ErrorPresenter, abychom načítali pokaždé jinou šablonu. Ujistíme se, že dědí od BasePresenteru a vesele začneme $this->locale používat. Jak nejrychleji nasimulovat chybu? Zapneme produkční prostředí a odkážeme na neexistující URL. Hele, nefunguje to. Po několikaminutovém hledání a zkoumání si potvrdíme, že do ErrorPresenteru se opravdu persistentní parametry nepředávají (v tomto případě).

Application\Application

Popišme si dvě situace, při kterých může dojít k "vyhození erroru".

  1. Chyba během aplikace - například zavolání neexistující metody $this->hello(); v HomepagePresenteru
  2. Chybná URL (Bad request)

Ad 1, $container->getByType('Nette\Application\Application')->run() - Tento kousek kódu zná každý. V metodě Application::run() se podle Htttp\Request vytvoří Application\Request, který už vede na konkrétní Presenter. Na Presenteru se pak zavolá ::run(). My jsme však v Presenteru způsobili chybu zavoláním neexistující metody...

Ad 2, Application::run() běží stejně, jako v prvním případě. Aplikace chce vytvořit Application\Request, ale už tady selže, bum...

Předchozí situace se rozejdou na řádku Application.php s voláním $this->processRequest($this->createInitialRequest());. Poprvé se stihne úspěšně zavolat Application::createInitialRequest() a teprve při zpracování požadavku aplikace umře. Podruhé Application::processRequest() nevrátí požadovaný request s patřičnými parametry - těsně před vrácením requestu vyhodí BadRequestException. V první situaci se tedy do Presenteru stihnou propsat náležité parametry a v ErrorPresenteru můžeme lokalizovat pomocí persistentní property $locale. A teď bychom rádi dostali parametr i do druhé situace.

Routříčku, otřes se

Application\Request se tvoří na začátku metody Application::createInitialRequest() nehledě na to, zda je cíl požadavku dostupný či ne. Pokud máme připravenou nějakou "fallback routu" pro určení alespoň lokalizace (na základě hostu, apod), můžeme se pokusit získat znovu Application\Request, aniž bychom se ho snažili protlačit k životu. Někde tedy znovu zavoláme Application::router->match(Http\Request); a pokusíme se ve vráceném požadavku najít naše parametry.

Nette\Object

Ať už pomocí Kdyby\Events, nebo jinak si zaregistrujeme událost Application::onError. Událost se v případě chyby spustí a jako argument dostaneme instanci Application a vyhozenou Exception. Událost bude muset odněkud získat Http\Request. Pomocí knihovny Kdyby\Events si ji jednoduše předáme pomocí konstruktoru. Když máme událost připravenou, něco do ní napíšeme:

public function onError(Application $application, Exception $exception)
{
	$application_request = $application->router->match($this->httpRequest);
	$request_parameters = $application_request->getParameters();
	$locale = $request_parameters['locale'];
}

Tím jsme sice získali kýžený parametr, ale v ErrorPresenteru stále není. Nejjednodušší cestu vidím v uložení parametru do session (kterou si předáme konstruktorem) a načtení parametru ze session v ErrorPresenteru. Cest je samozřejmě mnoho. Vyberte si tedy vaši.

Přidat komentář

Tento web používá k poskytování služeb a analýze návštěvnosti soubory cookie. Používáním tohoto webu s tím souhlasíte. V pořádku Další informace