Routovaní všech požadavků na jeden presenter?

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

Omlouvám se za blbý dotaz ale nějak mi není jasné jak vyřešit následující problém.
Čistě hypoteticky, pokud bych chtěl redakční systém, který by ukládal obsah jednotlivých stránek a podstránek webu do nějaké db tabulky, např z formuláře v administraci, zároveň by mne nechal vytvářet sekce i podsekce webu (ktere by byly take v db), URL adresy by potom mohli vypadat např. takto

http://example.com/…odsekce1/145
http://example.com/…odsekce2/145
http://example.com/…odsekce3/145
http://example.com/…ekce1/314554

(http://example.com/ – <sekce> – <podsekce> – <podpodsekce> – <ID>)

Já bych to asi normálně bez nette řešil tak, že bych si někde v index.php parsoval URL adresu a pote hledal konkretní stránku v databázi, pokud bych ji nenašel vyhodil bych něco jako BadRequestException respektive bych vrátil 404, pokud bych konkrétni stránku našel, poslal bych ji nějaké universální šabloně a ta by ji zobrazila.

Jak to řešit v nette?

Představoval bych si nějakou universální routu, která by jakýkoliv dotaz směrovala na jeden jediný universální presenter, který by rozhodl (dle DB) zdali vyhodí BadRequestException nebo stránku předá universální šabloně. Jenže, nette v bootstrapu vytvoří objekt application zavolá metodu run a v ní pak

<?php
$presenter = $request->getPresenterName();
try {
	$class = $this->getPresenterLoader()->getPresenterClass($presenter);
	$request->setPresenterName($presenter);
} catch (InvalidPresenterException $e) {
	throw new BadRequestException($e->getMessage(), 404, $e);
}
$request->freeze()
?>

Což vyhodí samozřejmě vyjímku, protože presenter sekce1Presenter.php neexistuje, navíc by se podsekce mohla brat jako action a to je nežádoucí.

Do metody run zasahovat nelze, zasah do boostrapu taky asi neni uplne koser. Jedina moznost je tedy napsat si nejakou routu, ktera preroutuje jakykoliv pozadavek na universalni presenter (ktery se zepta modelu zdali stranka s timto ID existuje). Nebo někoho napadne ještě nějaké lepší řešení?

Díky za každou radu.

Editoval geb (7. 9. 2012 17:14)

duke
Člen | 650
+
0
-

Výjimku ti to vyhazuje proto, protože používáš routu, která interpretuje ‚sekce1‘ z url jako název presenteru. Tzn. nepoužívej routy, které routují jinak, než potřebuješ. A co se týče tvé otázky, zda někdo nevymyslí lepší řešení, než řešit routování pomocí rout, tak si troufnu tvrdit, že nevymyslí. A editovat bootstrap se neboj, ten není součástí nette, ale tvojí aplikace.

geb
Člen | 6
+
0
-

Díky za odpověď duke, možná jsem to blbě formuloval, možná nerozumíš psanému textu ale tím „lepším řešením“ jsem myslel třeba úplně jiný návrhový vzor, než jsem popsal, který by řešil danou problematiku RS. Nicméně, otázka nezněla proč to vyhazuje exception, dokonce jsem to v tom textu i napsal „Což vyhodí samozřejmě vyjímku, protože presenter sekce1Presenter.php neexistuje, navíc by se podsekce mohla brat jako action a to je nežádoucí.“ Paradigma celé věci je, jak napsat pravidlo, které jakýkoliv požadavek směruje na jeden konkrétni presenter? Možná je to trivka ale mne to teď bohužel nedochází :(

Bootstrap se upravovat nebojím ale stejně bych na jeho konci volal metodu run() která se pokusí vytvořit objekt neexistujiciho presenteru.

Díky.

Editoval geb (7. 9. 2012 17:12)

Marek Šneberger
Člen | 130
+
0
-

Asi to bude na vlastní Router, koukal jsi se sem( teoreticky nekonečná url )?

geb
Člen | 6
+
0
-

Marku, díky, to je přesně to co jsem hledal, bohužel nenašel. Toto vlákno můžete tedy smazat.
Ještě jednou Díky.

geb
Člen | 6
+
0
-

Abych řekl pravdu tak po podrobném prostudování vlákna „teoreticky nekonečná url“, jsem trochu překvapen, řešení to je ale očekával jsem, že to nette umí řešit elegantněji, nativně. Zkusím něco vymyslet a popřípadě to sem doplnit. Docela by mne zajímalo jakej názor na tuto problematiku má David? Vždyt to musí řešit téměř každý větší web např. csfd.cz

Editoval geb (7. 9. 2012 17:36)

duke
Člen | 650
+
0
-

Routu, která vede vždy na tentýž presenter a tutéž akci můžeš nadefinovat např. takto:

$route = new Route('<section>/<subsection>/<subsubsection>/<id [0-9]+>', array(
    'presenter' => 'Universal',
    'action' => 'default',
));

Toto ve finále povede na volání UniversalPresenter::actionDefault a UniversalPresenter::renderDefault.

Nevýhodou této routy však je, že všechny uvedené parametry v routě jsou povinné. Pokud bys chtěl mít některé i nepovinné, bylo by to složitější (do jisté míry lze toto řešit pomocí hranatých závorek v definici routy, ale můžeš narazit na problémy s nejednoznačností). Pokud bys chtěl mít neomezenou hloubku hierarchie sekcí, tak už by bylo nutné napsat si vlastní speciální třídu implementující interface Nette\Application\IRouter a tu pak používat místo výchozí Nette\Application\Routers\Route.

Co se týče metody run na konci bootstrapu, tak ta pracuje se zaregistrovanými routami a prostřednictvím nich zjistí, jakýže objekt má instanciovat. Pokud neexistující, pak je chyba v routě.

geb
Člen | 6
+
0
-

Díky, po všech uvahách jsem se rozhodl napsat si vlastní router, IRouter je celkem sympatickej z hlediska implementace (pouze 2 metody, lze jim vykrást některé vnitřnosti z Nette\Application\Routers\Route), ale kam tu nově vzniklou třídu DbRoute správně umistit v hiearchii skeletona? zbytek snad pořeší RobotLoader.

Editoval geb (7. 9. 2012 21:17)

duke
Člen | 650
+
0
-

Z hlediska funkčnosti ji můžeš umístit kamkoli, kde ji RobotLoader najde. Z hlediska toho, kam logicky patří, tak nejspíš do app\routers\DbRoute.php či např. do libs\geb\routers\DbRoute.php (pokud ji v nějaké základní podobě hodláš sdílet mezi vícero projekty).