Prefix cesty – chyba dokumentace + chyba v routě
- m.brecher
- Generous Backer | 864
Ahoj,
mám dvě poznámky
1. router prefix cesty – dokumentace
cca před rokem a půl jsem zkoušel routu s prefixem cesty tak jak to je v dokumentaci – tj. s lomítkem na začátku prefixu (jestli si dobře pamatuji) a fungovalo to:
https://doc.nette.org/…tion/routing#…
ukázka z dokumentace:
$router->withPath('/eshop')
->addRoute('rss', 'Feed:rss')
Ale když jsem to nyní (nette/routing v3.0.3) testoval, tak ta verze s lomítkem na začátku prefixu nefunguje, zatímco verze bez lomítka funguje:
$router->withPath('/admin')
->addRoute('<presenter>/<action>[/<id>]', 'Entry:default'); // /admin/ No route for HTTP request
$router->withPath('admin')
->addRoute('<presenter>/<action>[/<id>]', 'Entry:default'); // /admin/ 200 OK, Entry:default
Zřejmě došlo k opravě lomítka v prefixu cesty, protože lomítko by na začátku být opravdu nemělo, ale v dokumentaci to zůstalo postaru?
2. chyba v routě
Tato samotná routa funguje:
$router->addRoute('[<slug>]', 'Front:default'); // /abc Front:default, slug = 'abc'
Ale v kombinaci s druhou routou s prefixem cesty už nefunguje jak by měla:
$router->withPath('admin')
->addRoute('<presenter>/<action>[/<id>]', 'Entry:default'); #?
$router->addRoute('[<slug>]', 'Front:default'); // /abc přesměruje na /admin/front/?slug=abc
Stejně dopadne i jednodušší zápis s prefixem cesty:
$router->addRoute('admin/<presenter>/<action>[/<id>]', 'Entry:default'); #?
$router->addRoute('[<slug>]', 'Front:default'); // /abc přesměruje na /admin/front/?slug=abc
Tato jednoduchá kolekce dvou rout by měla fungovat tak, že všechny routy s prefixem /admin/ zachytí první routa a všechny ostatní druhá routa.
Vypadá to tak, že možná došlo v poslední verzi Nette k žádoucí opravě prefixu cesty tak, aby byl v souladu s ostatnímu pravidly – tedy bez lomítka na začátku, ale přitom došlo ke změně funkce.
V podstatě chci úplně jednoduchý systém url pro malinký webík, kde administrace není v samostatném modulu -je to pár presenterů a presentery administrace jsou přístupné přes prefix v url /admin. Veřejná část webu má jeden presenter Front s jednou akcí default a přijímá jeden parametr slug.
Prosím pokročilé znalce routování o vyjádření zda se mýlím a nevidím nějakou vlastní chybu, nebo je opravdu nějaká chyba v routeru.
Díky
Editoval m.brecher (11. 1. 2023 14:28)
- David Grudl
- Nette Core | 8218
Samozřejmě v dokumentaci může být překlep, pošli prosím opravu s odstraněním toho lomítka. Na konci každé stránky je k tomu návod.
Proč to přesměrovává je vysvětlené tady https://doc.nette.org/…tion/routing#….
- m.brecher
- Generous Backer | 864
@DavidGrudl
dokumentace
pošli prosím opravu s odstraněním toho lomítka
OK pošlu
údajná chyba přesměrování
Proč to přesměrovává je vysvětlené tady
No seděl jsem nad tím další půlhodinu a nakonec jsem došel k závěru, že tam opravdu chyba není, i když to vypadalo že je. Router sice použije tu routu, kde první najde shodu a routy za ní ignoruje, ALE někdy i routa která následuje za routou která se použije ovlivňuje chování a tohle dělá problémy odhadnout.
Postupoval jsem takto
$router->addRoute('admin/<presenter>/<action>[/<id>]', 'Entry:default');
/admin přesměruje na /admin/
/admin/ mapuje na Entry:default
/admyn/ nesouhlasí prefix ⇒ No route for HTTP request
/ žádný prefix ⇒ No route for HTTP request
Chování je logické – pokud je prefix jiný, nebo žádný, router tuto routu ZAHODÍ
To se změní, když přidáme další routu:
$router->addRoute('admin/<presenter>/<action>[/<id>]', 'Entry:default');
$router->addRoute('', 'Front:content');
Routu pro Front:content dávám za routu s prefixem, protože jsem si v předchozím kroku otestoval, že první routa url bez prefixu zahodí.
Ne, nefunguje to tak, jak bychom očekávali:
/admin/ mapuje na Entry:default
/ přesměruje na /admin/front/content
Takže takhle to na první pohled vypadá, že specifičtější routa:
$router->addRoute('', 'Front:content');
je „přepsaná“ obecnější routou:
$router->addRoute('admin/<presenter>/<action>[/<id>]', 'Entry:default');
Router vyhodnotí obecnější routu jako kanonickou a přesměruje na ni. No nemá cenu s tím polemizovat, tak to je a je potřeba se s tím smířit. Navíc v dokumentaci je doporučeno řadit routy za sebou nejprve specifické, potom obecné – to jsme zde udělali obráceně a tak máme problém s přesměrováním.
Zkusme experimentovat, prohoďme pořadí rout – podle dokumentace nejprve specifickou, pak obecnou:
$router->addRoute('', 'Front:content');
$router->addRoute('admin/<presenter>/<action>[/<id>]', 'Entry:default');
/ mapuje na Front:content
/admin přesměruje na /admin/
/admin/ mapuje na Entry:default
Juch !! Funguje to jak potřebujeme – router mapuje Front:content na / a ostatní presentery na prefix /admin/.
Pro vícestránkový web bude potřeba předat do Front:content parametr slug:
$router->addRoute('[<slug>]', 'Front:content');
$router->addRoute('admin/<presenter>/<action>[/<id>]', 'Entry:default');
/ mapuje na Front:content, slug = null
/admin/ přesměruje na /admin
/admin mapuje na Front:content, slug = admin
Ano, toho jsme se obávali a proto jsme nejprve zkoušeli dát routu pro Front:content nakonec. Co s tím? Zkusme vyloučit hodnotu ‚admin‘ parametru slug:
$router->addRoute('[<slug (?!admin).*>]', 'Front:content');
$router->addRoute('admin/<presenter>/<action>[/<id>]', 'Entry:default');
/ mapuje na Front:content, slug = null
/admin přesměruje na /admin/
/admin/ mapuje na Entry:default
Hmmm… tak jednoduchý, že to jednodušší být nemůže a dělá to přesně to, co potřebuju. Ale strávil jsem na tom HODINU :)
Editoval m.brecher (11. 1. 2023 23:47)
- David Grudl
- Nette Core | 8218
Ale strávil jsem na tom HODINU :)
To není nic neobvyklého, tím si prošel opravdu každý :)
Víc jsem rozepsal v dokumentaci to pořadí rout, snad je to srozumitelné https://doc.nette.org/…tion/routing#…