3. úroveň odkazu v RouterFactory

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

Ahoj všichni, narazil jsem na jeden problém a vůbec nevím, jak jej vyřešit. Existují v Nette odkazy „3. úrovně“? (Nevím, jak lépe to nazvat)

Příklad:

Budu mít Linux, v něm distribuci a v distribuci dané téma.
Odkaz by vypadal nějak takto: http://mojedomena.cz/linux/ubuntu/tutorialy

Což tedy znamená, že linux bude presenter, ubuntu bude action a tutorialy už nevím.

Předpokládám, že to budu muset nastavit v routě.

public static function createRouter()
{
	$frontModule = new RouteList('Front');
	$frontModule[] = new Route('<linux>/<ubuntu>/<action>', ''); // Střílím
	$frontModule[] = new Route('<presenter>/<action>', 'Home:default');

	$router = new RouteList;
	$router[] = $frontModule;
	return $router;
}

Nebo už to třetí musí být bráno jako parametr?

$frontModule[] = new Route('<linux>/<ubuntu>[/<param1>]', ''); //Kam by to pak odkazovalo?

Budu moc vděčný za ukázku a vysvětlení.

CZechBoY
Člen | 3608
+
0
-

Tak samozrejme zalezi na tobe, z toho co si napsal neni uplne jasny co se snazis udelat…

3 (a vic) urovne bez parametry jdou udelat pres modul-presenter-action, případně moduly-submodul-presenter-default akce.

Spis to ale vypada ze hledas 1 presenter s 1 parametrem a to bude cesta k clanku/kategorii clanku?

ForestCZE
Člen | 209
+
0
-

Tak to, že není jasné, co chci udělat, bude tím, že sám nevím. Nevím/nevěděl jsem, jaké jsou možnosti. Jeden presenter by byl ideální.

CZechBoY
Člen | 3608
+
0
-

Tak popis co programujes :-)

ForestCZE
Člen | 209
+
-1
-

CZechBoY napsal(a):

Tak popis co programujes :-)

Popsal jsem. Odkaz „3. úrovně“. Dal jsem příklad odkazu, jak potřebuji, aby vypadal.

http://mojedomena.cz/linux/ubuntu/tutorialy

Kde linux je kategorie, ubuntu je podkategorie a tutorialy je okruh příspěvků, které vytáhnu z databáze. Co víc k tomu říct?

CZechBoY
Člen | 3608
+
+2
-

No ty si napsal, že chceš odkaz 3. úrovně a to se dá chápat milion způsoby :-)

https://pla.nette.org/…tr-s-lomitky

ForestCZE
Člen | 209
+
0
-

Tak jsem to zkusil takto:

public static function createRouter()
{
	$frontModule = new RouteList('Front');
	$frontModule[] = new Route('<presenter>/<action>', 'Home:default');

	$frontModule[] = new Route("<tutorialy>", [
		"presenter" => "Linux",
		"action" => "ubuntu",
		"tutorialy" => [
			Route::FILTER_OUT => null,
			Route::PATTERN => ".*?"
		]
	]);

	$router = new RouteList;
	$router[] = $frontModule;
	return $router;
}

A vyleze mi z toho: http://mojedomena.cz/linux/ubuntu?tutorialy=linux%2Fubuntu%2Ftutorialy%2F

Co dělám špatně?

Editoval ForestCZE (3. 5. 2018 12:18)

CZechBoY
Člen | 3608
+
0
-

Přehoď pořadí rout.

ForestCZE
Člen | 209
+
0
-

CZechBoY napsal(a):

Přehoď pořadí rout.

To jsem původně měl, ale hodí mi to dva redirecty, pokud zadám do prohlížeče: http://mojedomena.cz/, tak mě to přesměruje na: http://mojedomena.cz/linux/ubuntu/

EDIT: A navíc když kliknu na jakýkoliv odkaz, tak URL je v pohodě, ale načte se Front:Linux:ubuntu

Vážně si nevím rady, omlouvám se a děkuji za trpělivost, především @CZechBoY

Editoval ForestCZE (3. 5. 2018 14:08)

duke
Člen | 650
+
+1
-

@ForestCZE To lze vyřešit tak, že routě s maskou <tutorialy> přidáš FILTER_IN filtrovací funkci, kde odfiltruješ všechny hodnoty, které nejsou tutoriály (vrátíš null). Tím, že to neděláš, tak ta routa přijímá cokoli (což nechceš). To následné přesměrování je pak důsledek toho, že Nette kvůli kanonickým (neduplicitním) url v zájmu SEO přesměrovává na url, generované touto (prioritní) routou.

ForestCZE
Člen | 209
+
0
-

@duke Chápu, jak to myslíš, ale nevím, jak to napsat. Mohl bys mi s tím prosím pomoct? Už tak jsem rád, že jsem dal dohromady to, co mám teď. Moc díky.

duke
Člen | 650
+
+1
-

ForestCZE napsal(a):

@duke Chápu, jak to myslíš, ale nevím, jak to napsat. Mohl bys mi s tím prosím pomoct? Už tak jsem rád, že jsem dal dohromady to, co mám teď. Moc díky.

$frontModule[] = new Route("<tutorialy>", [
	"presenter" => "Linux",
	"action" => "ubuntu",
	"tutorialy" => [
		// $tutorials je služba, která umí ověřit, zda existuje tutorial s daným url
		Route::FILTER_IN => function ($tutorialy) use ($tutorials) {
			return $tutorials->exists($tutorialy) ? $tutorialy : null;
		},
		Route::FILTER_OUT => null,
		Route::PATTERN => ".*?"
	]
]);
duke
Člen | 650
+
0
-

Ještě tedy nechápu to:

    "presenter" => "Linux",
    "action" => "ubuntu",

Tam bys měl mít spíš jen:

	"presenter" => "Tutorials",
	"action" => "default",
ForestCZE
Člen | 209
+
0
-

duke napsal(a):

Ještě tedy nechápu to:

    "presenter" => "Linux",
    "action" => "ubuntu",

Tam bys měl mít spíš jen:

	"presenter" => "Tutorials",
	"action" => "default",

@duke No já právě nevím, jestli to mám dobře.

Mám presenter: presenters/LinuxPresenter.php a pak template: presenters/templates/Linux/ubuntu.latte, což znamená, že ta cesta bude: neco.cz/linux/ubuntu a pak potřebuji rozdělení té ubuntu:

/linux/ubuntu/tutorialy
/linux/ubuntu/necodalsiho1
/linux/ubuntu/necodalsiho2

Pak mi právě není jasné, proč je presenterem Tutorials a ne Linux

duke
Člen | 650
+
0
-

No máš minimálně dvě možnosti. Buď to vše bude řešit jeden presenter Tutorials, který bude mít parametr obsahující cestu, tj.:

class TutorialsPresenter extends BasePresenter
{
	/** @var string @persistent */
	public $path;

	public function renderDefault($path)
	{
		// TODO: podle $path nastavit šablonu a její obsah
		//       v $path bude např. "linux/ubuntu/instalace
	}
}

s routováním:

$frontModule[] = new Route("<path>", [
	"presenter" => "Tutorials",
	"action" => "default",
	"path" => [
		Route::FILTER_IN => function ($path) use ($tutorials) {
		return $tutorials->exists($path) ? $path : null;
		},
		Route::FILTER_OUT => null,
		Route::PATTERN => ".*?"
	]
]);

Nebo to řešit individuálními presentery a akcemi:

class LinuxPresenter extends BasePresenter
{
	/** @var string @persistent */
	public $topic;

	public function renderUbuntu($topic)
	{
		// TODO: podle $topic nastavit šablonu a její obsah
		//       v $topic bude např. "instalace"
	}

	public function renderFedora($topic)
	{
		// TODO: podle $topic nastavit šablonu a její obsah
		//       v $topic bude např. "instalace"
	}
}

s routováním:

$frontModule[] = new Route("<presenter>/<action>/<topic>", [
	"topic" => [
        Route::FILTER_OUT => null,
        Route::PATTERN => ".*?"
    ],
	null => [
        Route::FILTER_IN => function (array $params) use ($tutorials) {
            return $tutorials->exists("$params[presenter]/$params[action]/$params[topic]")) ? $params : null;
        }
    ],
]);

Netestováno, takže to může obsahovat nějaký chyby, či nedomyšlenosti. Ale snad jsem tě alespoň nasměroval…
Já bych spíše zvolil tu první variantu. Tzn. to rozdělení do šablon bych řešil v té render metodě, než pro toto „zneužívat“ akce a presentery.

ForestCZE
Člen | 209
+
0
-

@duke Ta první varianta, kdy to vše řeší jeden presenter, se mi zamlouvá víc.

U té routy nikde nevidím definici proměnné $tutorials a vůbec nevím, kde se bere.

Co se týká nastavení šablony v presenteru – podle cesty nastavit:

$this->setView('sablona')

?

duke
Člen | 650
+
0
-

$tutorials je služba, kterou si tam přidáš přes dependency injection. Např. nějaký repozitář či fasáda řešící tutorialy.

Co se týče nastavení šablony, tak k tomu slouží metoda formatTemplateFiles, která vrací pole cest k šablonám, ze kterého se vezme první existující. Můžeš ji tedy překrýt např. takto:

	public function formatTemplateFiles()
	{
		$filePaths = parent::formatTemplateFiles();
		array_unshift($filePaths, __DIR__ . "/templates/{$this->path}.latte");
		return $filePaths;
	}

Asi by bylo ale dobré zkontrolovat, zda $this->path neobsahuje něco, co nemá…

Metoda setView se volá zpravidla v action metodách a umožňuje nastavit, která render metoda se bude následně volat. Nicméně to má dopad i na to, co pak vrací výchozí implementace metody formatTemplateFiles, takže ano, i setView metodu lze k tomuto teoreticky použít, byť to v tomto případě nedoporučuji (potenciální problémy s lomítky v hodnotě view, atp.).

Editoval duke (3. 5. 2018 23:39)