ErrorPresenter a moduly – chyby generování odkazů?
- BigCharlie
- Člen | 283
Mám aplikaci, dva moduly: Admin, Front. V bootstrapu nastaveno
<?php
$application->errorPresenter = 'Front:Error';
$application->catchExceptions = TRUE;
?>
Problém je, že pokud dojde k chybě, kterou simuluji (nyní konkrétně BadRequestException), nevygeneruje se správně link {plink :Front:About:} z šablony FrontModule\@layout.phtml. Totéž, pokud ho napíšu přímo do šablony FronModule\Error\default.phtml. Zároveň se ztrácí persistentní parametry, ovšem to už je řešeno někde na fóru (teď ten odkaz nemůžu najít).
Pokud odstraním nastavení error presenteru a nasimuluji požadavek na
ErrorPresent, je odkaz v pořádku. A metoda renderDefault ErrorPresenteru
mám zatím prázdnou.
Má někdo potuchy, proč je tomu tak a co s tím?
Zapomněl jsem napsat, že chybová hláška místo odkazu je „error: No route for :Front:About:default()“
Ještě jeden poznatek – odkaz do Admin modulu funguje bez problému. To jsem z toho jelen.
Editoval BigCharlie (26. 6. 2009 16:08)
- PetrP
- Člen | 587
Budeš muset poslat nějakou zmenšenou mini applikačku která to děla, protože jsem si simuloval to co píšeš (jestli jsem to dobře pochopil) a bez problému, takže jestli tak bude chyba jinde.
Teď když ještě jednou koukám co píšeš:
error: No route for :Front:About:default()
máš skutečně pro
tohle routu?
- BigCharlie
- Člen | 283
Budeš muset poslat nějakou zmenšenou mini applikačku která to děla, protože jsem si simuloval to co píšeš (jestli jsem to dobře pochopil) a bez problému, takže jestli tak bude chyba jinde.
Teď když ještě jednou koukám co píšeš:
error: No route for :Front:About:default()
máš skutečně pro tohle routu?
Tak jsem zkusil upravit skeleton tak, abych ty chybu vyprovokoval. Jen jsem v něm vytvořil dva moduly, Front a Admin. Tady je celý ten příklad. Stačí zkusit třeba adresu /cs/aa a odkaz „O nás“ neexistuje, místo něj je ta hláška.
Chyba je určitě v routování, ale jak to vyřešit? Moje stávající routy jsou:
<?php
$router[] = new Route('index.php', array('module' => 'Front', 'presenter' => 'Homepage', 'action' => 'default'), Route::ONE_WAY);
$router[] = new Route('', array('lang' => 'cs', 'module' => 'Front', 'presenter' => 'Homepage', 'action' => 'default'), Route::ONE_WAY);
$router[] = new Route('admin/<presenter>/<action>/', array('module' => 'Admin', 'presenter' => 'Indexer', 'action' => 'default'));
$router[] = new Route('<lang cs|en>/<presenter>/<action>/', array('module' => 'Front', 'presenter' => 'Homepage', 'action' => 'default'));
?>
A představa taková:
- všechno, co začíná „/admin/“ sežere Admin modul
- Front modul je dvojjazyčný (cs, en)
- neexistuje bezjazyčná verze, ta je přesměrována na českou
Kde dělám chybu? To routování mi motá hlavu.
- PetrP
- Člen | 587
Takže postupně:
Neprve mimo tuto chybu pozor na absolutni/ralativni cesty
require '/Nette/loader.php';
Se může hledat prakticky
kdekoliv.
require LIBS_DIR.'/Nette/loader.php';
Je už jistější.
Routa pro index.php nemá určenou hodnotu pro lang, takže nefunguje. Rovnou jde spojit z tou následující (prázdnou) přes foo parametr tedy:
$router[] = new Route('<? index\.php|>', array(
'lang' => 'cs',
'module' => 'Front',
'presenter' => 'Homepage',
'action' => 'default'
), Route::ONE_WAY);
Když aplikace volá errorPresenter, tak zahazuje všechny params z routy, a
tedy nemá $lang.
(skus si Debug::dump($presenter->lang)
) a k vytvoření routy
pro :Front:* potřebuješ lang. Takže si ho v error presenteru nastav na
defaultní $presenter->lang = 'cs';
pak se ti už routa
použije.
V :Admin: bude zase problém ten, že nemá parametr lang takže se nemá jaká routa pouzít.
Nebo řešení pro všechny tyto problémy (i v té routě z index.php nemusíš mít lang):
$router[] = new Route('<presenter>/<action>/', array(
'module' => 'Front',
'presenter' => 'Homepage',
'action' => 'default'
));
A v BasePresenter::startup()
public function startup()
{
if ($this->lang === NULL)
$this->lang = $this->getHttpRequest()->detectLanguage(array('cs','en'));
}
Tedy detekci výchozího jazyka.
Potřebuješ na to mít zaplou
$presenter->autoCanonicalize = true;
(defaultně je
na true)
- BigCharlie
- Člen | 283
Čím to, že teď mi to připadá prosté ;-) Dík moc za polopatické vysvětlení, problém je vyřešen.
I ty routy mi připadají o něco jasnější.
- David Grudl
- Nette Core | 8228
PetrP napsal(a):
To že se do errorPresenteru nepřenašejí params, je bug nebo úmysl?
Nějak to pořeším, už to kdysi hlásil Washo.
- BigCharlie
- Člen | 283
Testoval jsem dnes rev. 1eb2dca na problém se zahazováním parametrů v ErrorPresenteru a chování se zdá být stále stejné. Minul jsem něco, nebo se zatím nic nezměnilo?
Po úpravě, kterou navrhuje PetrP se zdá být vše OK. Úprava v současné revizi na tomto řádku.
- Dimitry
- Člen | 11
Zdravím,
používám aktuální verzi Nette (version 2.0-dev released on 2011–02–03), která je ke stažení pod odkazem Download, ale s tímto problémem se stále potýkám. Můj Error presenter neobdrží $lang, je v něm NULL. U ostatních presenterů to funguje.
Díval jsem se do repozitáře aktuální verze i do Nette ve své aplikaci, ale ten navrhovaný fix tam není.
Edit: Když si to tam sám nahradím, tak to začne fungovat dle mých představ.
Editoval Dimitry (13. 2. 2011 23:25)
- Dimitry
- Člen | 11
Vím, že byl opraven, ale mě se děje stále. To je právěže divné.
Lang je persistentní. Používám i doporučovanější syntaxi bez zavináčů:
<?php
use \Nette,
\Nette\Application\Presenter,
\Nette\Environment,
\Nette\Debug;
/**
* Zakladni presenter cele aplikace.
*/
abstract class BasePresenter extends Presenter {
public $lang;
/**
* Zajistuje spravu persistentnich parametru.
* @return array Pole persistentnich parametru.
*/
public static function getPersistentParams() {
return array('lang');
}
/**
* Startovani vychoziho presenteru.
*/
protected function startup() {
parent::startup();
Debug::barDump($this->lang);
// Zvaliduje se jazyk. Pokud je nevalidni, vstoupi se na vychozi.
$langs = Environment::getVariable('lang');
if (!in_array($this->lang, $langs->toArray())) {
$this->lang = $langs[0];
}
// Jazyk se preda sablone.
$this->template->lang = $this->lang;
// Nastavi se jazyk Translatoru.
Environment::getService('Translator')->setLang($this->lang);
}
protected function createTemplate() {
$template = parent::createTemplate();
$template->setTranslator(Environment::getService('Translator'));
return $template;
}
}
?>
Nad tím mám ještě jednen abstraktní presenter:
<?php
abstract class BaseFrontPresenter extends BasePresenter {
protected function startup() {
parent::startup();
$this->setLayout('front');
}
}
?>
A samotný error presenter vypadá takhle:
<?php
/**
* Chybový presenter reprezentující výjimky.
*/
final class ErrorPresenter extends BaseFrontPresenter {
public function __construct() {
parent::__construct();
}
public function actionDefault($exception) {
Nette\Debug::log($exception, Nette\Debug::ERROR);
if ($this->isAjax()) {
// jedná-li se o ajax, zaznamená se chyba payloadu
$this->payload->error = TRUE;
} elseif ($exception instanceof \Nette\Application\BadRequestException) {
// přejde se na šablonu pro 404
$this->view = '404';
} else {
// přejde se na šablonu pro 500
$this->view = '500';
Nette\Debug::processException($exception);
}
}
}
?>
Ostatní presentery frontendu také dědí od BaseFrontPresenter a přitom se v nich persistení $lang přenáší. Pouze Error presenter ho nedostane.