Jak lépe nadefinovat routu?
- BigCharlie
- Člen | 283
Mám problém s přenosem parametru mnou definovaného parametru lang. V base presenteru je nastaven jako persistentní. Error presenter dědí z base presenteru.
Někde je ale chyba
www.domain.cz/existujici-akce // OK
www.domain.cz/neexistujici-akce // OK - přesměruje na error presenter, lang = cz
www.domain.cz/neexistujici.cokoliv // tečka = FAIL - error presenter má lang = NULL
Přišel jsem na to tak, že mám požadavek na soubor, který již neexistuje. Podle mě by to mělo být zachyceno Error presenterem. ale dostávám „No route for HTTP request“. Kde mám chybu?
Nastavení routeru
$router[] = new Route('//www.domain.<lang cz|sk>/index.php', 'Homepage:default', Route::ONE_WAY);
$router[] = new Route('//www.domain.<lang cz|sk>/<action>', 'Homepage:default');
- BigCharlie
- Člen | 283
Ještě jsem se na to podíval a moc netuším, co teď. Pokud je můj požadavek s takto stanovenými routami třeba na www.domain.cz/sitemap.xml (který neexistuje), výsledkem je správně BadRequestException.
Následuje tedy přesměrování na ErrorPresenter – to je taky v pořádku. Protože se jedná o vícejazyčný web, mám upravené funkce formatLayoutTemplateFiles, formatTemplateFiles. A tady dochází k problému.
V ErrorPresenteru je lang prázdný, volá se neexistující šablona – Výsledkem je ApplicationException (Page not found. Missing template ‚…/templates/Error/.404.latte‘).
Kam se ten jazyk poděl? (šablona se jmenuje buď cz.404.latte, nebo sk.404.latte). A proč je tomu tak pouze v tomto případě (tehdy, když site obsahuje jiné než alfanumerické znaky). Není to chyba?
- BigCharlie
- Člen | 283
Protože mi to nedá, vrtal jsem se v tom a myslím, že už to začínám trochu chápat.
Při požadavku na www.domain.cz/neexistujici
je všechno
v pořádku, protože to vyhoví nějaké routě. Ta přesměruje na presenter,
ten zjistí, že action neexistuje, vyhodí BadRequestException a předá
presenteru. Vše funguje správně, parametry jsou z url vyextrahovány.
Při požadavku na www.domain.cz/cosi.html
není v pořádku
nic. Téhle routě
$router[] = new Route('//www.domain.<lang cz|sk>/<action>', 'Homepage:default');
to nevyhoví. Další není, takže se sice vyhodí BadRequestException, ovšem není z čeho parametry extrahovat, nevyhovělo se routě.
Tím jsem si vysvětlil příčinu. Může mi někdo poradit, jak to tedy mám udělat? Napadá mě nadefinovat routu
$router[] = new Route('//www.domain.<lang cz|sk>/<slug>', 'Homepage:default');
Slug v metodě default zkontroluju – pokud bude existovat template nebo metoda, zobrazím/provedu. Jinak vyhodím BadRequestException.
Nějak se mi to nezdá, poradí někdo něco elegantnějšího? Předem dík.
Edit: Ještě bych poprosil nějakého moderátora, zda může vlákno přesunout do sekce routování.
Editoval BigCharlie (12. 3. 2011 18:22)
- BigCharlie
- Člen | 283
Tak jsem to nakonec udělal úplně jinak. V ErrorPresenteru kontroluju ve startupu, zda existuje jazyk. Pokud ne, tak se doplní pomocí následující konstrukce:
if (!$this->lang) {
$tempRequest = new HttpRequest(new UriScript(new Uri(Environment::getHttpRequest()->getUri()->getBaseUri())));
$params = Environment::getApplication()->getRouter()->match($tempRequest)->getParams();
$this->lang = $params['lang'];
}
Třeba to někomu pomůže. A díky všem za spolupráci :-) Pokud někoho napadne něco elegantnějšího, sem s tím, prosím.
- David Grudl
- Nette Core | 8218
Přemýšlím nad tím už týden a nic mě nenapadlo. Ale je to zcela reálný problém.
- Filip Procházka
- Moderator | 4668
Co takhle něco jako ?
$router = $application->getRouter();
// ...
// fallback routa
$router[] = new Route('//www.domain.<lang cz|sk>/<address .*?>', 'MyError:404');
- kravčo
- Člen | 721
Možno:
<?php
use Nette\Environment,
Nette\Application\Route;
...
$lang = end(explode('.', Environment::getHttpRequest()->getUri()->getHost()));
// validate...
$router[] = new Route("//www.domain.$lang/index.php", array(
'presenter' => 'Homepage',
// 'action' => 'default',
'lang' => $lang,
), Route::ONE_WAY);
$router[] = new Route("//www.domain.$lang/<action>", array(
'presenter' => 'Homepage',
// 'action' => 'default',
'lang' => $lang,
));
- BigCharlie
- Člen | 283
Řešit to na úrovni rout mi nepřipadalo správné.
Ono to trochu smrdí tím, že ErrorPresenter se vlastně „konfiguruje“ pro případ neobvyklých situací. Podle mě by odpovědnost měla ležet na ErrorPresenteru, protože jde o chybovou situaci, kterou má umět řešit.
- Filip Procházka
- Moderator | 4668
Co je špatně na mém řešení? Pokud se udělá přesměrování v klasickém ErrorPresenteru Forwardem na uživatelský (aby se neprala ta podmínka v application) můžeš mít jeden MyErrorPresenter na celou aplikaci. Je proto možné využít fallback routu
- BigCharlie
- Člen | 283
HospiLan: Asi nic, jen se mi to nějak nelíbilo. Ale pravdu máte v tom, že pokud změním routování, musím myslet na změnu v ErrorPresenteru.
Ještě dotaz – proč je v tom tvém řešení další error presenter? Nestačilo by směrovat na stávající a metodu mu přidat? Kde je ten problém, který nevidím?
Nerozumím moc tomu, proč přesměrovávat z ErrorPresenteru na MyError – tak daleko evidentně mé znalosti nette nesahají. Co by se tím způsobilo? Dík za objasnění.
- BigCharlie
- Člen | 283
Asi mě musíš víc postrčit – když bych tu routu směřoval přímo na stávající ErrorPresenter a vynechal MyError, tak podmínce nevyhovím?
- Filip Procházka
- Moderator | 4668
Musíš nadefinovat ErrorPresenter
pro Application
,
ale když ho nadefinuješ, už na něj nemůžeš odkazovat, protože to
zakazuje Application
. Řešením je mít 2×
ErrorPresenter
. Jeden pro application, který přesměruje
požadavky na vlastní ErrorPresenter
, ne který půjde
i přesměrovávat, protože nebude registrovaný v
Application
.
Je to postavené na hlavu, ale mělo by to fungovat :)
- Aurielle
- Člen | 1281
Co využít dědičnosti?
class ErrorPresenter extends Nette\Application\Presenter {
// Registrován jako $app->errorPresenter = 'Error';
// ...
}
namespace FrontModule;
final class ErrorPresenter extends \ErrorPresenter {}
Jinak v té podmínce v Application vidím zcela jasný účel, ErrorPresenter by neměl být dosažitelný z venku – mimojiné právě proto, že očekává instanci \Exception a ne HTTP vstup. Sám jsem si tuhle podmínku implementoval pro další ErrorPresentery pro jednotlivé moduly…
Editoval gmvasek (1. 4. 2011 16:45)