Routovaní všech požadavků na jeden presenter?
- geb
- Člen | 6
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
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
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
Asi to bude na vlastní Router, koukal jsi se sem( teoreticky nekonečná url )?
- geb
- Člen | 6
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
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
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)