Vytváření odkazů URL
Tvořit odkazy v Nette je jednoduché, jako ukazovat prstem. Stačí jen namířit a framework už za vás všechnu práci udělá. Ukážeme si:
- jak vytvářet odkazy v šablonách i jinde
- jak odlišit odkaz na aktuální stránku
- co s neplatnými odkazy
Díky obousměrnému routování nebudete nikdy muset do šablon či kódu zapisovat navrdo URL adresy vaší aplikace, které se mohou později měnit, nebo je komplikovaně skládat. V odkazu stačí uvést presenter a akci, předat případné parametry a framework už URL vygeneruje sám. Vlastně je to velice podobné, jako když voláte funkci. To se vám bude líbit.
V šabloně presenteru
Nejčastěji vytváříme odkazy v šablonách a skvělým pomocníkem je atribut n:href
:
<a n:href="Product:show">detail</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 název presenteru a akce.
Kliknutí na odkaz je, zjednodušeně řečeno, něco jako zavolání metody ProductPresenter::renderShow()
.
A pokud má ve své signatuře parametry, můžeme ji volat s argumenty:
<a n:href="Product:show $product->id, $product->slug">detail produktu</a>
Na rozdíl od PHP 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 $product->id, lang => cs">detail produktu</a>
Pokud metoda ProductPresenter::renderShow()
nemá $lang
ve své signatuře, může si hodnotu
parametru zjistit pomocí $lang = $this->getParameter('lang')
.
Pokud jsou parametry uložené v poli, lze je rozvinout operátorem (expand)
(něco jako ...
operátor v PHP, ale funguje s asociativními poli):
{var $args = [$product->id, lang => cs]}
<a n:href="Product:show (expand) $args">detail produktu</a>
V odkazech se také automaticky předávají tzv. persistentní parametry.
Atribut n:href
je velmi šikovný pro HTML značky <a>
. Chceme-li odkaz vypsat jinde,
například v textu, použijeme {link}
:
Adresa je: {link Homepage:default}
V kódu
K vytvoření odkazu v presenteru slouží metoda link()
:
$url = $this->link('Product:show', $product->id);
Parametry lze předat také pomocí pole, kde lze uvést i pojmenované parametry:
$url = $this->link('Product:show', [$product->id, 'lang' => 'cs']);
Odkazy lze vytvářet i bez presenteru, od toho je tu LinkGenerator a jeho metoda
link()
.
Odkazy na presenter
Pokud je cílem odkazu presenter a akce, má tuto syntaxi:
[//] [[[[:]module:]presenter:]action | this] [#fragment]
Formát podporují všechny značky Latte a všechny metody presenteru, které s odkazy pracují, tedy n:href
,
{link}
, {plink}
, link()
, lazyLink()
, isLinkCurrent()
,
redirect()
, redirectPermanent()
, forward()
, canonicalize()
a také LinkGenerator. Takže i když je v příkladech použit n:href
, mohla by tam být
kterákoliv z funkcí.
Základním tvarem je tedy Presenter:action
:
<a n:href="Homepage:default">úvodní stránka</a>
Pokud odkazujeme na akci aktuálního presenteru, můžeme jeho název vynechat:
<a n:href="default">úvodní stránka</a>
Pokud je cílem akce default
, můžeme ji vynechat, ale dvojtečka musí zůstat:
<a n:href="Homepage:">úvodní stránka</a>
Odkazy mohou také směřovat do jiných modulů. Zde se odkazy rozlišují na relativní do
zanořeného submodulu, nebo absolutní. Princip je analogický k cestám na disku, jen místo lomítek jsou dvojtečky.
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
.
<a n:href="this">refresh</a>
Odkazovat můžeme na určitou část stránky přes tzv. fragment za znakem mřížky #
:
<a n:href="Homepage:#main">odkaz na Homepage:default a fragment #main</a>
Absolutní cesty
Odkazy generované pomocí link()
nebo n:href
jsou vždy absolutní cesty (tj. začínají znakem
/
), ale nikoliv absolutní URL s protokolem a doménou jako https://domain
.
Pro vygenerování absolutní URL přidejte na začátek dvě lomítka (např. n:href="//Homepage:"
). Nebo lze
přepnout presenter, aby generoval jen absolutní odkazy nastavením $this->absoluteUrls = true
.
Odkaz na aktuální stránku
Cíl this
vytvoří odkaz na aktuální stránku:
<a n:href="this">refresh</a>
Zároveň se přenáší i všechny parametry uvedené v signatuře render<View>()
nebo
action<Action>()
metody. Takže pokud jsme na stránce Product:show
a id: 123
, odkaz
na this
předá i tento parameter.
Samozřejmě je možné parametry specifikovat přímo:
<a n:href="this refresh: 1">refresh</a>
Metoda presenteru isLinkCurrent()
zjišťuje, zda je cíl odkazu shodný s aktuální stránkou. Toho lze
využít například v šabloně k odlišení odkazů apod.
Parametry jsou stejné jako u metody link()
, navíc je však možné místo konkrétní akce uvést zástupný
znak *
, který znamená jakoukoliv akci daného presenteru.
{if !$presenter->isLinkCurrent('Admin:login')}
<a n:href="Admin:login">Přihlaste se</a>
{/if}
<li n:class="$presenter->isLinkCurrent('Product:*') ? active">
<a n:href="Product:">...</a>
</li>
V kombinaci s n:href
v jednom elementu se dá použít zkrácená podoba:
<a n:class="$presenter->isLinkCurrent() ? active" n:href="Homepage:">...</a>
Odkazy na signál
Cílem odkazu nemusí být jen presenter a akce, ale také signál (volají metodu
handle<Signal>()
). Pak je syntaxe následující:
[//] [sub-component:]signal! [#fragment]
Signál tedy odlišuje vykřičník:
<a n:href="click!">signal</a>
Lze vytvořit i odkaz na signál subkomponenty (nebo sub-subkomponenty):
<a n:href="componentName:click!">signal</a>
Odkazy v komponentě
Protože komponenty jsou samostatné znovupoužitelné celky, které by neměly mít žádné
vazby na okolní presentery, fungují tu odkazy trošku jinak. Atribut Latte n:href
a značka {link}
i metody komponent jako je link()
a další považují cíl odkazu vždy za název signálu. Proto není
nutné ani uvádět vykřičník:
<a n:href="click">signál, nikoliv akce</a>
Pokud bychom chtěli v šabloně komponenty odkazovat na presentery, použijeme k tomu značku {plink}
:
<a href="{plink Homepage:default}">úvod</a>
nebo v kódu
$this->getPresenter()->link('Homepage:default')
Neplatné odkazy
Může se stát, že vytvoříme neplatný odkaz – buď proto, že vede na neexistující presenter, nebo proto, že
předává víc parametrů, než které cílová metoda přijímá ve své signatuře, 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 skriptuPresenter::INVALID_LINK_TEXTUAL
– vizuální varování, vypíše chybu přímo do odkazuPresenter::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
LinkGenerator
Jak vytvářet odkazy s podobným komfortem jako má metoda link()
, ale bez přítomnosti presenteru? Od toho je
tu Nette\Application\LinkGenerator.
LinkGenerátor je služba, kterou si můžete nechat předat přes konstruktor a poté vytvářet odkazy jeho metodou
link()
.
Oproti presenterům je tu rozdíl. LinkGenerator vytváří všechny odkazy rovnou jako absolutní URL. A dále neexistuje
žádný „aktuální presenter“, takže nelze jako cíl uvést jen název akce link('default')
nebo uvádět
relativní cesty k modulům.
Neplatné odkazy vždy vyhazují Nette\Application\UI\InvalidLinkException
.