ErrorPresenter a moduly – chyby generování odkazů?

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

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

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

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

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)

PetrP
Člen | 587
+
0
-

Teďka dotaz na ostatní:
To že se do errorPresenteru nepřenašejí params, je bug nebo úmysl?
Šlo by to jednoduše fixnout zde
přidaním:

	array_merge(isset($request)?$request->getParams():array(),array('exception' => $e))

(popřípadě něčím hezčím, podobně funkčním)

BigCharlie
Člen | 283
+
0
-

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

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

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.

David Grudl
Nette Core | 8228
+
0
-

fixed

Dimitry
Člen | 11
+
0
-

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)

Aurielle
Člen | 1281
+
0
-

Máš lang označen jako persistentní? Jinak daný problém byl již opraven…

Dimitry
Člen | 11
+
0
-

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.