Jedna routa na dva různé prezentery

mkoula
Backer | 57
+
0
-

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. 14:44)

Kamil Valenta
Člen | 815
+
0
-
$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
+
0
-

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

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. 14:56)

mkoula
Backer | 57
+
0
-

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. 23:17)

m.brecher
Generous Backer | 863
+
0
-

@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 | 815
+
+1
-

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 | 863
+
-2
-

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

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 | 1260
+
+3
-

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. 20:50)

Kamil Valenta
Člen | 815
+
0
-

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

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. 10:54)