Vytváření odkazů

Vytvoření odkazů patří mezi nejsilnější místa Nette Frameworku. Díky obousměrnému routování není potřeba do šablon či kódu natvrdo zapisovat URL nebo je komplikovaně skládat. Stačí se odkazovat na akce presenterů, předávat jim parametry a framework už URL vygeneruje sám. Vytvořit odkaz je pak stejně snadné, jako zavolat funkci. To se vám bude tuze líbit!

Během programování a vytváření šablon nás nemusí zajímat tvar URL adres, budeme se totiž odkazovat přímo na akci presenteru, tj. například na již zmíněnou Product:show.

Odkazy v šablonách

Nejčastěji vytváříme odkazy v šablonách. Aby to bylo co nejjednodušší, nabízí nám framework hned tři cesty. Nejšikovnější z nich je n:href

<a n:href="Product:show $productId">detail produktu</a>

Všimněte si, že místo HTML atributu href jsme použili n:atribut n:href. Jeho hodnotou pak není URL, jak by tomu bylo v případě atributu href, ale rovnou akce presenteru. Tam má tvar

[Presenter:]action [,] [arg1] [, arg2] [, ...]

Po kliknutí na odkaz se dostane ke slovu metoda ProductPresenter::renderShow() a jako parametr $id ji bude předána hodnota proměnné $productId. Parametrů bychom mohli předat i víc, stejně jako když voláme metodu. Mohlo by to být snad jednodušší?

Doporučuje se dodržovat konvenci velkého prvního písmenka pro název presenteru a malého pro akci. Jako oddělovač slouží právě jedna dvojtečka.

Kromě toho je možné předávat i pojmenované parametry. Následující odkaz předává parametr lang s hodnotou cs:

<a n:href="Product:show $productId, lang => cs">detail produktu</a>

Ačkoliv metoda renderShow nemá $lang ve své hlavičce, může hodnotu parametru zjistit voláním $lang = $this->getParameter('lang').

Máme-li všechny parametry v poli, můžeme jej rozvinout operátorem (expand):

{var $args = [$productId, lang => cs]}
<a n:href="Product:show (expand) $args">detail produktu</a>

Pokud je šablona, ve které vytváříme odkaz, také součástí Product presenteru, můžeme název presenteru vynechat a psát přímo n:href="show $productId". Nebo obráceně, vede-li odkaz na akci nazvanou default, lze tuto vynechat a napsat n:href="Product: $id" (nezapomeňte na dvojtečku).

Odkazy mohou také směřovat do jiných modulů. Zde se rozlišuje, zda se odkazujeme „relativně“ do zanořeného submodulu, nebo „absolutně“ do jiného modulu – pak cesta začne dvojtečkou. Pro ukázku předpokládejme, že aktuální presenter je součástí modulu Front, potom zapíšeme:

<a n:href="Shop:Product:show">odkaz na Front:Shop:Product:show</a>
<a n:href=":Admin:Product:show">odkaz na Admin:Product:show</a>

Speciálním případem je odkaz na sebe sama, kdy jako cíl uvedeme this.

Vygenerovaný odkaz má podobu relativní cesty. Pokud potřebujeme absolutní odkaz včetně domény, přidáme na začátek dvě lomítka (např. n:href="//show $productId"). Pokud nastavíme v presenteru proměnnou $absoluteUrls na true, budou všechny od té chvíle generované odkazy absolutní.

Odkazovat můžeme na určitou část na stránce přes tzv. fragment za znakem křížky #:

<a n:href="show#comments">odkaz na Product:show a fragment #comments</a>

Atribut n:href je velmi šikovný, pokud vytváříme HTML značku <a>. Chceme-li odkaz vypsat jinde, například v textu šablony, použijeme {link} se stejnou vnitřní syntaxí:

Adresa je: {link Product:show $productId}

Přečtěte si další podrobnosti o syntaxi Latte šablon.

Odkaz na aktuální stránku

Presenter může snadno zjistit, zda je cíl odkazu shodný s aktuální stránkou. Toho lze využít například v šabloně layoutu k přidání CSS třídy k odkazům na aktuální stránku nebo změně obsahu stránky.

Využívá se k tomu metoda $presenter->isLinkCurrent(destination [,arg [,arg ...]]).

Místo konkrétní akce je možné uvést zástupný znak *, který znamená jakoukoliv akci daného presenteru.

<ul class="menu">
	<li n:class="$presenter->isLinkCurrent('Product:show') ? active">
		<a n:href="Product:show">...</a>
	</li>

	<!-- uvnitř elementu A není nutné opakovat cíl odkazu: -->
	<li><a n:class="$presenter->isLinkCurrent() ? active" n:href="Product:detail">...</a></li>

	<!-- rozšíření scope: -->
	<li n:class="$presenter->isLinkCurrent('Product:*') ? active">
		<a n:href="Product:detail">...</a>
	</li>
</ul>

{if !$presenter->isLinkCurrent('Admin:login')}
	<a n:href="Admin:login">Přihlaste se!</a>
{/if}

Zástupný znak * lze použít pouze místo akce, nikoliv presenteru. Pro zjištění, zda odkazujeme na aktuální modul (nebo jeho submodul), použijeme metodu $presenter->isModuleCurrent(moduleName).

<ul class="menu">
	<li n:class="$presenter->isModuleCurrent('MyEshop:Users') ? active">
		Uživatelé
		<ul class="submenu">
			<li><a n:href="MyEshop:Users:Search:default">Hledat</a></li>
			<li><a n:href="MyEshop:Users:Add:default">Nový uživatel</a></li>
		</ul>
	</li>
</ul>

Odkazování v presenteru

Presenter a komponenta disponují metodou link(), pomocí které lze vytvářet odkazy podobně jako v šabloně. Prvním parametrem je cílová akce presenteru, následují předávané argumenty:

$url = $this->link(destination [,arg [,arg ...]]);

Ty lze předat také pomocí pole. Příklady:

$url = $this->link('Product:show', $productId);

$url = $this->link('Product:show', [$productId, 'lang' => 'cs']);

Pokud při generování odkazu předáte parametru metody hodnotu false, do odkazu se vůbec nepřidá. Řešením je definovat pro parametr výchozí hodnotu true nebo false. Nette pak pochopí, že je typu boolean, a předávanou hodnotu změní na 1 nebo 0 a následně při zpracování requestu je presenter převede zpět na boolean.

Neplatné odkazy

Může se stát, že vytvoříme neplatný odkaz – buď proto, že vede na neexistující presenter, proto, že předává víc parametrů, než které cílová metoda přijímá ve své definici, nebo když pro cílovou akci nelze vygenerovat URL. Jak naložit s neplatnými odkazy určuje statická proměnná Presenter::$invalidLinkMode. Ta může nabývat kombinaci těchto hodnot (konstant):

  • Presenter::INVALID_LINK_SILENT – tichý režim, jako URL se vrátí znak #
  • Presenter::INVALID_LINK_WARNING – vyhodí se varování E_USER_WARNING, které bude v produkčním režimu zalogováno, ale nezpůsobí přerušení běhu skriptu
  • Presenter::INVALID_LINK_TEXTUAL – vizuální varování, vypíše chybu přímo do odkazu
  • Presenter::INVALID_LINK_EXCEPTION – vyhodí se výjimka InvalidLinkException

Výchozí nastavení je INVALID_LINK_WARNING v produkčním režimu a INVALID_LINK_WARNING | INVALID_LINK_TEXTUAL ve vývojovém. INVALID_LINK_WARNING v produkčním prostředí nezpůsobí přerušení skriptu, ale varování bude zalogováno. Ve vývojovém prostředí ho zachytí Tracy a zobrazí bluescreen. INVALID_LINK_TEXTUAL pracuje tak, že jako URL vrátí chybovou zprávu, která začíná znaky #error:. Aby takové odkazy byly na první pohled patrné, doplníme si do CSS:

a[href^="#error:"] {
	background: red;
	color: white;
}

Pokud nechceme, aby se ve vývojovém prostředí produkovala varování, můžeme nastavit tichý režim přímo v konfiguraci.

application:
	silentLinks: true