Vlastní formátování odkazů

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

Předem upozorňuji že jsem pracně procházel většinu fóra a odpoveď jsem nenašel… :)

Moje otázka je jak pracovat s vytvářením odkazů pomocí funkce link() – potřeboval bych vytvořit něco takového – www.example.com/…ejaky-clanek, a zatím to dělám způsobem {$presenter->link('clanky/'.$article->redirect)}, ale nejsem si jistý jestli je to nejlepší způsob… Navíc mám pocit že tímto způsobem nejsem schopen očetřit aby „clanky“ byly hned za rootem webu, ale budou vždy až pod modulem/presenterem pod který patří – a to je právě ten problém který řeším, protože zatím mě to generuje akorát www.example.com/…ejaky-clanek, coz mi moc nevyhovuje…

Pak se toto týká ještě druhá věc, a to nastavení routeru, a to jestli je pro potřebu těch článků nastaven správně:

$router[] = new Route('clanky/<id>', array(
	'presenter' => 'Default',
	'action' => 'article',
	'id' => NULL,
));

Předem děkuji za všechny rady :)

xificurk
Člen | 121
+
0
-

A co takhle?

<?php
$control->link(':Default:article', array('id' => $articleID));
?>
David Grudl
Nette Core | 8145
+
0
-

Nejprve bych rád ujasnil, že parametry metody link() nesouvisí přímo s URL. Prvním argumentem je cíl (destination) určující cílový presenter & view, druhým (resp. dalšími) jsou parametry předávané tomuto presenteru:

$link->(destination [,arg [,arg ...]])

kde destination je
'anotherView' (odkaz na aktuální presenter a anotherView)
'AnotherPresenter:anotherView' (odkaz na AnotherPresenter a anotherView)
'AnotherPresenter:' (ozkaz na AnotherPresenter a výchozí view ‚default‘)
'AnotherModule:Presenter:view' (odkaz do jiného modulu)
Parametry presenteru je možné předat jako asociativní pole
$this->link('show', array('id' => 10, 'lang' => 'en'))

Asociativní pole není příliš sexy, proto Nette nabízí vychytávku: pokud existuje v cílovém presenteru metoda renderShow($id, $lang, ...) nebo metoda actionShow($id, $lang, ...), kde ono ‚show‘ v názvu odpovídá názvu linkovaného view, je možné klíče ‚id‘ a ‚lang‘ vynechat – automaticky se vezmou z parametrů těchto metod:

$this->link('show', array(10, 'en'))

A naopak, když je dotyčná metoda po odkliknutí zavolána, tak se jí předají tyto argumenty v parametrech $id a $lang. V poli je možné uvést další parametry, které metody renderShow a actionShow nedefinují, například lze nastavit nějaký persistentní parametr (v tom případě ovšem už s asociativním klíčem). Pokud žádný takový další parametr není, je možné pole úplně vynechat:

$this->link('show', 10, 'en')

Tedy v Nette se odkazuje na presenter & view, nebo ještě jednodušeji: odkazuje se na konkrétní metodu. $this->link('catalog:show', 10, 'en') odkazuje a po odkliknutí zavolá metodu CatalogPresenter::renderShow(10, 'en'). Jaké se vytvoří URL v tu chvíli nehraje roli. To je úkol oddělené vrstvy – routování.

David Grudl
Nette Core | 8145
+
0
-

tomas.lang napsal(a):

Pak se toto týká ještě druhá věc, a to nastavení routeru, a to jestli je pro potřebu těch článků nastaven správně:

$router[] = new Route('clanky/<id>', array(
	'presenter' => 'Default',
	'action' => 'article',
	'id' => NULL,
));

Předem děkuji za všechny rady :)

To je správné nastavení. Ale je potřeba počítat s tím, že i URL clanky/ je vyhovující a bude v proměnné $id hodnota NULL.

Ještě taková obecná drobnost – presenter by neměl mít název Default, stejně jako třídu ve svém projektu nenazveme Default, nebo (byť jedinou) funkci nějaké třídy nenazveme function default(). Nebylo by lepší třeba Homepage?

tomas.lang
Člen | 53
+
0
-

#2: no ale v tomto případě si přeci nepomůžu, protože ztratím to slovo clanky které jsem v URL chtěl mít…

#3: takže pokud jsem to správně pochopil tak při používání funkce link() se zajímám jen o to na který presenter, resp. pohled chci odkázat… Takže v tom případě by můj kód měl vypadat pouze takto:

$presenter->link('article', array('id' => $article->redirect))

ale jak mám pomocí routerů docílit té kýžené adresy – to už nějak nechápu…

#4: a pokud bych do toho zápisu routeru neuvedl 'id' => NULL, pak by si to při URL clanky/ ten router nepřivlastnil?

S těmi názvy default je to tak že jsem to celé dneska narychlo předelávat z ukázkové příkladu, a tam se to skoro všude jmenuje default :) Mno, je to můj první den s nette, tak jsem se zatím spíše věnoval výzkumu… Homepage zní velice rozumně… :)

Editoval tomas.lang (12. 8. 2008 22:42)

David Grudl
Nette Core | 8145
+
0
-

tomas.lang napsal(a):

#3: takže pokud jsem to správně pochopil tak při používání funkce link() se zajímám jen o to na který presenter, resp. pohled chci odkázat… Takže v tom případě by můj kód měl vypadat pouze takto:

$presenter->link('article', array('id' => $article->redirect))

Ano. Jen pro jistotu doplním, že $presenter->link('article', ...) vede na současný presenter a view ‚article‘.

ale jak mám pomocí routerů docílit té kýžené adresy – to už nějak nechápu…

Mně ten router připadá v pořádku, měl by generovat adresy ve tvaru http://www.example.com/clanky/nejaky-clanek

#4: a pokud bych do toho zápisu routeru neuvedl 'id' => NULL, pak by si to při URL clanky/ ten router nepřivlastnil?

Přesně tak, id by se stalo povinným parametrem a takovéto URL bez něj by nebylo kompletní a tudíž vyhovující. Aplikace by zkoušela další routy v seznamu a pokud by žádné nevyhovovalo, zobrazila by se chyba 404 Not found.

S těmi názvy default je to tak že jsem to celé dneska narychlo předelávat z ukázkové příkladu, a tam se to skoro všude jmenuje default :) Mno, je to můj první den s nette, tak jsem se zatím spíše věnoval výzkumu… Homepage zní velice rozumně… :)

Jasně, to se vás netýkalo, to byl obecný postřeh.

tomas.lang
Člen | 53
+
0
-

Sláva! Vše začalo fungovat tak jak má :) Mnohokráté díky…

Ještě bych se chtěl zeptat jestli záleží na tom v jakém pořadí jsou routery uloženy – uvedu na příkladu:

$router[] = new Route('clanky/<id>', array(
	'presenter' => 'Default',
	'action' => 'article',
));
$router[] = new Route('<presenter>/<action>/<id>', array(
	'presenter' => 'Default',
	'action' => 'default',
	'id' => NULL,
));
$router[] = new Route('<presenter>/<action>/<id>', array(
	'presenter' => 'Default',
	'action' => 'default',
	'id' => NULL,
));
$router[] = new Route('clanky/<id>', array(
	'presenter' => 'Default',
	'action' => 'article',
));

je v rámci fungování aplikace mezi těmito dvěma kódy rozdíl?

A poslední otázka (snad) se ještě týká trochu off-topis třídy DibiTable – jde o metodu kterou zpracovávám ten redirect na ty články

	public function renderArticle( $id )
	{
		$articles = new Articles;
		$article = $articles->fetch( array( '[redirect]='. $id ) );

		$this->template->title = "Article";
		$this->template->article = $article;
	}

Jde o to jestly by šlo ten fetch napsat nějak rozumněji – tedy něco ve stylu ->fetch( array( '[redirect]=%s', $id ) ) – abych tam ty uvozovky nemusel doplňovat ručně… Samozřejmě bych mohl udělat přímo SQL dotaz přes dibi a měl bych po problému, ale když už tu mám tu třídu Articles, tak bych ji rád využil… :)

David Grudl
Nette Core | 8145
+
0
-

Na pořadí záleží, zpracovávají se od shora dolů, takže url /clanky/nejaky-clanek v druhém příkladu se předá na presenter ‚clanky‘ a view ‚nejaky-clanek‘, druhá routa se nedostane ke slovu.

ad dibi: momentálně na to nejsem naladěn, nevím, odpovím později.

pmg
Člen | 372
+
0
-

Jak víte, libuju si v navážení se do cizích diskusí, zvlášť pokud se jedná o offtopic. Když tedy padla zmínka o DibiTable, nebylo by pěkné, dyby s ní bylo propojeno DibiFluent? Vím, ono je to ještě ve zkušebním provozu, ale jen navrhuji. Představte si to, byla by to magická kombinace… Ale asi jsem zase objevil kolo. Dnes už páté! Hádejte, kde.

Editoval pmg (13. 8. 2008 11:50)

Panda
Člen | 569
+
0
-

tomas.lang napsal(a):

A poslední otázka (snad) se ještě týká trochu off-topis třídy DibiTable – jde o metodu kterou zpracovávám ten redirect na ty články

	public function renderArticle( $id )
	{
		$articles = new Articles;
		$article = $articles->fetch( array( '[redirect]='. $id ) );

		$this->template->title = "Article";
		$this->template->article = $article;
	}

Jde o to jestly by šlo ten fetch napsat nějak rozumněji – tedy něco ve stylu ->fetch( array( '[redirect]=%s', $id ) ) – abych tam ty uvozovky nemusel doplňovat ručně… Samozřejmě bych mohl udělat přímo SQL dotaz přes dibi a měl bych po problému, ale když už tu mám tu třídu Articles, tak bych ji rád využil… :)

Mělo by se to chovat stejně inteligentně, jako třeba modifikátory %v nebo %a, takže stačí asociativní pole sloupec => hodnota a typ sloupce fouknout za jeho název:

$article = $articles->fetch(array('redirect%s' => $id));

Pokud by bylo potřeba filtrovat třeba podle ID autora (uživatele), tak by to mohlo vypadat takto:

$article = $articles->fetch(array('author%i' => $id));

Pokud jsou parametry správně otypované (tzn. třeba číslo je integer a ne string), tak si dokonce můžeš dovolit modifikátory typu neuvádět:

$article = $articles->fetch(array('author' => 15));
/* SQL:
	SELECT *
	FROM `articles`
	WHERE `author`=15
*/

$article = $articles->fetch(array('author' => '15'));
/* SQL:
	SELECT *
	FROM `articles`
	WHERE `author`='15'
*/

Pokud však používáme nezpracovaný vstup přímo od klienta, tak bude lepší tam ten modifikátor uvést.

David Grudl
Nette Core | 8145
+
0
-

Panda napsal(a):

Pokud však používáme nezpracovaný vstup přímo od klienta, tak bude lepší tam ten modifikátor uvést.

A nebo $article = $articles->fetch(array('author' => (int) $id));

pmg napsal(a):

Jak víte, libuju si v navážení se do cizích diskusí, zvlášť pokud se jedná o offtopic. Když tedy padla zmínka o DibiTable, nebylo by pěkné, dyby s ní bylo propojeno DibiFluent? Vím, ono je to ještě ve zkušebním provozu, ale jen navrhuji. Představte si to, byla by to magická kombinace… Ale asi jsem zase objevil kolo. Dnes už páté! Hádejte, kde.

Je to velmi lákavé, ale zatím se mi to nepovedlo rozumně sloubit. Zádrhel je v tom, že DibiFluent vytvoří dotaz, který je potřeba nakonec spustit metodou execute(), což ovšem odporuje konvenci DibiTable.