Jak lépe nadefinovat routu?

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

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
+
0
-

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
+
0
-

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
+
0
-

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 | 8145
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

Ř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.

kravčo
Člen | 721
+
0
-

Problém nastane, ak budeš mať detekciu jazyka na dvoch miestach (definícia rout a Error prezenter) a potom routy zmeníš. Podľa mňa routa je práve na to, aby mi dala všetky parametre, ktoré potrebujem, nie aby som si ich musel hľadať sám ak sa to nepodarí…

Filip Procházka
Moderator | 4668
+
0
-

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
+
0
-

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í.

Filip Procházka
Moderator | 4668
+
0
-

Problém je, ve pro mě nepochopitelné podmínce, v Application

BigCharlie
Člen | 283
+
0
-

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
+
0
-

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
+
0
-

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)