Jedna routa na dva různé prezentery
- mkoula
- Backer | 57
Mám routu:
$router->addRoute('/[<lang en|de|it|fr>/]<id \d+>/<slug>', [
'presenter' => 'Accommodation',
'action' => 'default',
'lang' => 'en',
]);
Mám různá URL:
/107/hotel-denis
/308/hotel-hilton
/395/dream-yacht
/257/yacht-vpm-cocktail-creole
Potřeboval bych nějak udělat, aby pokud ve slugu existuje slovo
‚yacht‘ – vždy vše směřoval na YachtPresenter::default()
a cokoliv ostatního na AccommodationPresenter::defaut()
Hraju si už hodinu s různými filtry a prostě ne a ne. Varianta je si
udělat pro tuhle jednou routu vlastní router, ale pořád si říkám, že by
to snad nějak jít mohlo. Jednoduše to jde s návratovou funkcí, kam si
předám parameter, ale ta vrací už obsah.
Nenapadne někoho něco?
PS:
Jde to obějít v AccommodationPresenteru, ale pak Tracy neukáže správný Presenter a člověk nevidí kam to vede a musí chodit skrz kód. A já si říkám, že by to nějak jít mělo…
public function actionDefault(int $id, ?string $slug)
{
// Redirect to Yacht presenter if "yacht" is in the slug
if (str_contains($slug, 'yacht')) {
$this->forward('Yacht:default', ['id' => $id, 'slug' => $slug]);
}
....
}
Editoval mkoula (23. 9. 2024 14:44)
- Kamil Valenta
- Člen | 839
$router->addRoute('/[<lang en|de|it|fr>/]<id \d+>/<slug>-yacht', [
'presenter' => 'Yacht',
'action' => 'default',
'lang' => 'en',
]);
$router->addRoute('/[<lang en|de|it|fr>/]<id \d+>/<slug>', [
'presenter' => 'Accommodation',
'action' => 'default',
'lang' => 'en',
]);
Třeba jen takto?
- mkoula
- Backer | 57
Tohle mi bohužel změní stávající URL, kterou se snažím zachovat…
Kamil Valenta napsal(a):
$router->addRoute('/[<lang en|de|it|fr>/]<id \d+>/<slug>-yacht', [ 'presenter' => 'Yacht', 'action' => 'default', 'lang' => 'en', ]); $router->addRoute('/[<lang en|de|it|fr>/]<id \d+>/<slug>', [ 'presenter' => 'Accommodation', 'action' => 'default', 'lang' => 'en', ]);
Třeba jen takto?
- MajklNajt
- Člen | 516
a niečo na tento spôsob? (píšem z hlavy, netestoval som)
$router->addRoute('/[<lang en|de|it|fr>/]<id \d+>/<slug>', [
'presenter' => 'Accommodation',
'action' => 'default',
null => [
Route::FilterIn => function (array $params): array {
if (str_contains($params['slug'], 'yacht')) {
$params['presenter'] = 'Yacht';
}
return $params;
},
Route::FilterOut => function (array $params): array {
if (str_contains($params['slug'], 'yacht')) {
$params['presenter'] = 'Yacht';
}
return $params;
},
],
]);
Editoval MajklNajt (23. 9. 2024 14:56)
- mkoula
- Backer | 57
Tak mě to přesměruje na URL, které není v routingu, ale odpovídá
pravidlům routování:
/yacht/default/257?slug=yacht-vpm-cocktail-creole
Což také není co bych chtěl. V podstatě se zpracuje jen filter „out“. Ten změní presenter a snaží se to najít jinou routu pro Yacht, která nexistuje a vytvoří tohle…
MajklNajt napsal(a):
a niečo na tento spôsob? (píšem z hlavy, netestoval som)
$router->addRoute('/[<lang en|de|it|fr>/]<id \d+>/<slug>', [ 'presenter' => 'Accommodation', 'action' => 'default', null => [ Route::FilterIn => function (array $params): array { if (str_contains($params['slug'], 'yacht')) { $params['presenter'] = 'Yacht'; } return $params; }, Route::FilterOut => function (array $params): array { if (str_contains($params['slug'], 'yacht')) { $params['presenter'] = 'Yacht'; } return $params; }, ], ]);
Editoval mkoula (23. 9. 2024 23:17)
- m.brecher
- Generous Backer | 898
@mkoula
je nutné mít na vybrané klienty samostatný presenter ?? Nevidím do detailu, jaks se zpracování VIP yacht klientů liší, ale šel bych na to spíš tak, že bych zpracování rozvětvil až v AccommodationPresenter::default().
Popiš rozdíly ve zpracování více do hloubky, třeba něco vymyslíme.
- Kamil Valenta
- Člen | 839
mkoula napsal(a):
Tak mě to přesměruje na URL, které není v routingu, ale odpovídá pravidlům routování:
/yacht/default/257?slug=yacht-vpm-cocktail-creole
Což také není co bych chtěl. V podstatě se zpracuje jen filter „out“. Ten změní presenter a snaží se to najít jinou routu pro Yacht, která nexistuje a vytvoří tohle…
Ukaž, jak v linku vytváříš odkazy a ukaž ideální celou kolekci rout.
- m.brecher
- Generous Backer | 898
@mkoula
Ještě mě napadlo v AccommodationPresenter::default() analyzovat $slug a pokud obsahuje ‚yacht‘ provést redirect() na YachtPresenter::default(), pro který by se přidala routa třeba takhle:
$router->addRoute('/[<lang en|de|it|fr>/]/yacht/<id \d+>/<slug>', [
'presenter' => 'YachtPresenter',
'action' => 'default',
'lang' => 'en',
]);
- mkoula
- Backer | 57
To je podobné vyíz výše – cílem je neměnit stávající URL.
Ono stačí v Accommodation zavolat:
if (str_contains($slug, 'yacht')) {
$this->forward('Yacht:default', ['id' => $id, 'slug' => $slug]);
}
Pak to funguje i na stejné URL, jen Tracy tuto změnu nevidí a ukazuje,
že požadavek zpracovává AccommodationPresenter.
Asi chci moc :-)
Napsal jsem si vlastní AccommodationRouter jen pro tento příklad a v něm to funguje. Jen je to něco, co bych čekal, že půjde vyřešit ve standardním routování…
m.brecher napsal(a):
@mkoula
Ještě mě napadlo v AccommodationPresenter::default() analyzovat $slug a pokud obsahuje ‚yacht‘ provést redirect() na YachtPresenter::default(), pro který by se přidala routa třeba takhle:
$router->addRoute('/[<lang en|de|it|fr>/]/yacht/<id \d+>/<slug>', [ 'presenter' => 'YachtPresenter', 'action' => 'default', 'lang' => 'en', ]);
- Marek Bartoš
- Nette Blogger | 1306
Router zpracovává routy od první k poslední, při zpracování aktuální url i při jejím generování. Filtry jsou pouze mapování, spuštěné potom, co routu matchneš. Bez custom routy, která by se někam dotazovala zda ten záznam má, máš v routeru jen jednu možnost a to udělat adresu těch rout tak, aby nebyly zaměnitelné. To v tomhle případě lze tak, že si pro parametr <slug> definuješ regex, který vyžaduje, aby například slug končil na -yacht. A druhá routa by ideálně měla dělat přesný opak, aby i generování odkazu muselo jít přes ten správný presenter a slug -yacht ti neprošel i přes odkaz na accommodation presenter.
„Tracy tuto změnu nevidí a ukazuje, že požadavek zpracovává AccommodationPresenter“ – sounds like feature request
Editoval Marek Bartoš (24. 9. 2024 20:50)
- Kamil Valenta
- Člen | 839
Marek Bartoš napsal(a):
Filtry jsou pouze mapování, spuštěné potom, co routu matchneš.
Toto může působit nepřesným dojmem, že filtry neovlivní, zda se routa matchne. Takže jen doplnění, že filtry to ovlivnit mohou.
mkoula napsal(a):
cílem je neměnit stávající URL
Stále nám, neznámo proč, tajíš podobu {plink} nebo n:href a aktuální podobu celého routeru. To se pak těžko hledá způsob, který by ti nezměnil URL…
- mkoula
- Backer | 57
Thaaank youuu :-D
To je přesně ono a nějak mě to úplně nenapadlo, protože se snažím složitějším regulárům v routingu vyhýbat, ale když bude jeden, asi ok
$router->addRoute('/[<lang en|de|fr|it>/]<id \d+>[/<slug [^/]*yacht[^/]*>]', [
'presenter' => 'Yacht',
'action' => 'default',
'lang' => $this->init->getDefaultLanguage(),
]);
$router->addRoute('/[<lang en|de|fr|it>/]<id \d+>[/<slug>]', [
'presenter' => 'Accommodation',
'action' => 'default',
'lang' => $this->init->getDefaultLanguage(),
])
Regulár to pořeší a vše funguje. Napsal jsem si vlastní router, což fungovalo stejně, jen je to věc extra. Ke všemu používám komponenty a je třeba napsat router, aby podporoval generování query stringů, kteřé řeší signály v komponentách.
Řešení v klasickém Nette routingu je jednodušší na správu a závislosti…
Marek Bartoš napsal(a):
Router zpracovává routy od první k poslední, při zpracování aktuální url i při jejím generování. Filtry jsou pouze mapování, spuštěné potom, co routu matchneš. Bez custom routy, která by se někam dotazovala zda ten záznam má, máš v routeru jen jednu možnost a to udělat adresu těch rout tak, aby nebyly zaměnitelné. To v tomhle případě lze tak, že si pro parametr <slug> definuješ regex, který vyžaduje, aby například slug končil na -yacht. A druhá routa by ideálně měla dělat přesný opak, aby i generování odkazu muselo jít přes ten správný presenter a slug -yacht ti neprošel i přes odkaz na accommodation presenter.
„Tracy tuto změnu nevidí a ukazuje, že požadavek zpracovává AccommodationPresenter“ – sounds like feature request
Jinak @DavidGrudl → ono zachycení volání
$this->forward()
v Presenteru někde v TracyBaru by asi
opravdu stálo za nějaký feature request o:)
Editoval mkoula (25. 9. 2024 10:54)
- Quetic
- Člen | 2
mkoula napsal(a):
Mám routu:
$router->addRoute('/[<lang en|de|it|fr>/]<id \d+>/<slug>', [ 'presenter' => 'Accommodation', 'action' => 'default', 'lang' => 'en', ]);
Mám různá URL:
/107/hotel-denis
/308/hotel-hilton
/395/dream-yacht
/257/yacht-vpm-cocktail-creole. Mimochodem, když už řešíš takovéto projekty a chceš si někdy zpestřit chvíle mezi kódováním, doporučuji mrknout na nové cs2 skiny – skvělé místo, kde můžeš otevírat bedny s různými skiny a získávat unikátní výbavu do her. Je to skvělá zábava a příjemný relax mezi programováním.
>
Potřeboval bych nějak udělat, aby pokud ve slugu existuje slovo ‚yacht‘ – vždy vše směřoval na
YachtPresenter::default()
a cokoliv ostatního naAccommodationPresenter::defaut()
Hraju si už hodinu s různými filtry a prostě ne a ne. Varianta je si udělat pro tuhle jednou routu vlastní router, ale pořád si říkám, že by to snad nějak jít mohlo. Jednoduše to jde s návratovou funkcí, kam si předám parameter, ale ta vrací už obsah.
Nenapadne někoho něco?PS:
Jde to obějít v AccommodationPresenteru, ale pak Tracy neukáže správný Presenter a člověk nevidí kam to vede a musí chodit skrz kód. A já si říkám, že by to nějak jít mělo…
public function actionDefault(int $id, ?string $slug) { // Redirect to Yacht presenter if "yacht" is in the slug if (str_contains($slug, 'yacht')) { $this->forward('Yacht:default', ['id' => $id, 'slug' => $slug]); } .... }
Ahoj,
chápu, co chceš udělat, a taky mi to přijde jako ideální případ pro vlastní router nebo alespoň nějakou předzpracovací logiku v routeru. V Nette bohužel standardní addRoute neumí přímo podmíněné přesměrování podle obsahu parametru.
Jeden možný elegantní přístup je vytvořit vlastní router, který bude před parsováním URL kontrolovat, jestli ve slugu je „yacht“, a podle toho nastavit presenter:
php
class CustomRouter implements \Nette\Application\IRouter
{
private \Nette\Application\Routers\Route $defaultRoute;
private \Nette\Application\Routers\Route $yachtRoute;
public function __construct()
{
$this->defaultRoute = new \Nette\Application\Routers\Route('/[<lang en|de|it|fr>/]<id \d+>/<slug>', [
'presenter' => 'Accommodation',
'action' => 'default',
'lang' => 'en',
]);
$this->yachtRoute = new \Nette\Application\Routers\Route('/[<lang en|de|it|fr>/]<id \d+>/<slug>', [
'presenter' => 'Yacht',
'action' => 'default',
'lang' => 'en',
]);
}
public function match(\Nette\Http\IRequest $httpRequest): ?\Nette\Application\Request
{
$path = $httpRequest->getUrl()->getPath();
// Jednoduchá kontrola, jestli je ve URL "yacht"
if (strpos($path, 'yacht') !== false) {
return $this->yachtRoute->match($httpRequest);
}
return $this->defaultRoute->match($httpRequest);
}
public function constructUrl(\Nette\Application\Request $appRequest, \Nette\Http\Url $refUrl): ?string
{
if ($appRequest->getPresenterName() === 'Yacht') {
return $this->yachtRoute->constructUrl($appRequest, $refUrl);
}
return $this->defaultRoute->constructUrl($appRequest, $refUrl);
}
}
A v RouterFactory pak místo běžné routy použiješ tuto:
php
$router[] = new CustomRouter();
Výhodou je, že Tracy pak správně ukáže presenter podle URL, routing je čistý a srozumitelný a nemusíš dělat přesměrování v presenteru.
Jediná věc je, že v této implementaci hledáš „yacht“ v celé URL, takže pokud by mohl být v jiném segmentu než ve slug, můžeš ještě URL parsovat detailněji a kontrolovat jen konkrétní část.
Pokud bys to chtěl udělat opravdu jen pomocí addRoute, bohužel je to limitované a musíš řešit logiku uvnitř presenteru.
Doufám, že to pomůže!