Tworzenie linków URL

Tworzenie linków w Nette jest proste jak wskazywanie palcem. Wystarczy tylko wycelować, a framework już za Ciebie wykona całą pracę. Pokażemy:

  • jak tworzyć linki w szablonach i gdzie indziej
  • jak odróżnić link do aktualnej strony
  • co z nieprawidłowymi linkami

Dzięki dwukierunkowemu routingowi nigdy nie będziesz musiał w szablonach czy kodzie zapisywać na sztywno adresów URL Twojej aplikacji, które mogą się później zmienić, lub skomplikowanie je składać. W linku wystarczy podać presenter i akcję, przekazać ewentualne parametry, a framework już sam wygeneruje URL. Właściwie jest to bardzo podobne do wywoływania funkcji. Spodoba Ci się to.

W szablonie presentera

Najczęściej tworzymy linki w szablonach, a świetnym pomocnikiem jest atrybut n:href:

<a n:href="Product:show">szczegóły</a>

Zauważ, że zamiast atrybutu HTML href użyliśmy n:atrybutu n:href. Jego wartością nie jest URL, jak by to było w przypadku atrybutu href, ale nazwa presentera i akcji.

Kliknięcie na link jest, upraszczając, czymś w rodzaju wywołania metody ProductPresenter::renderShow(). A jeśli ma w swojej sygnaturze parametry, możemy ją wywołać z argumentami:

<a n:href="Product:show $product->id, $product->slug">szczegóły produktu</a>

Możliwe jest również przekazywanie parametrów nazwanych. Poniższy link przekazuje parametr lang o wartości cs:

<a n:href="Product:show $product->id, lang: cs">szczegóły produktu</a>

Jeśli metoda ProductPresenter::renderShow() nie ma $lang w swojej sygnaturze, może uzyskać wartość parametru za pomocą $lang = $this->getParameter('lang') lub z właściwości.

Jeśli parametry są przechowywane w tablicy, można je rozwinąć operatorem ... (w Latte 2.x operatorem (expand)):

{var $args = [$product->id, lang => cs]}
<a n:href="Product:show ...$args">szczegóły produktu</a>

W linkach automatycznie przekazywane są również tzw. parametry persistentne.

Atrybut n:href jest bardzo przydatny dla znaczników HTML <a>. Jeśli chcemy wypisać link gdzie indziej, na przykład w tekście, użyjemy {link}:

Adres to: {link Home:default}

W kodzie

Do tworzenia linku w presenterze służy metoda link():

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

Parametry można przekazać również za pomocą tablicy, gdzie można podać również parametry nazwane:

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

Linki można tworzyć również bez presentera, do tego służy LinkGenerator i jego metoda link().

Linki do presentera

Jeśli celem linku jest presenter i akcja, ma on następującą składnię:

[//] [[[[:]module:]presenter:]action | this] [#fragment]

Format ten obsługują wszystkie znaczniki Latte i wszystkie metody presentera, które pracują z linkami, czyli n:href, {link}, {plink}, link(), lazyLink(), isLinkCurrent(), redirect(), redirectPermanent(), forward(), canonicalize() oraz LinkGenerator. Więc nawet jeśli w przykładach użyto n:href, mogłaby tam być dowolna z tych funkcji.

Podstawową formą jest więc Presenter:action:

<a n:href="Home:default">strona główna</a>

Jeśli linkujemy do akcji aktualnego presentera, możemy pominąć jego nazwę:

<a n:href="default">strona główna</a>

Jeśli celem jest akcja default, możemy ją pominąć, ale dwukropek musi pozostać:

<a n:href="Home:">strona główna</a>

Linki mogą również prowadzić do innych modułów. Tutaj linki dzielą się na względne do zagnieżdżonego podmodułu lub absolutne. Zasada jest analogiczna do ścieżek na dysku, tylko zamiast ukośników są dwukropki. Załóżmy, że aktualny presenter jest częścią modułu Front, wtedy zapiszemy:

<a n:href="Shop:Product:show">link do Front:Shop:Product:show</a>
<a n:href=":Admin:Product:show">link do Admin:Product:show</a>

Specjalnym przypadkiem jest link do siebie samego, gdy jako cel podamy this.

<a n:href="this">odśwież</a>

Możemy linkować do określonej części strony za pomocą tzw. fragmentu za znakiem kratki #:

<a n:href="Home:#main">link do Home:default i fragmentu #main</a>

Ścieżki absolutne

Linki generowane za pomocą link() lub n:href są zawsze ścieżkami absolutnymi (tj. zaczynają się znakiem /), ale nie są absolutnymi URL z protokołem i domeną, jak https://domain.

Aby wygenerować absolutny URL, dodaj na początku dwie ukośniki (np. n:href="//Home:"). Lub można przełączyć presenter, aby generował tylko linki absolutne, ustawiając $this->absoluteUrls = true.

Cel this tworzy link do aktualnej strony:

<a n:href="this">odśwież</a>

Jednocześnie przekazywane są wszystkie parametry podane w sygnaturze metody action<Action>() lub render<View>(), jeśli action<Action>() nie jest zdefiniowana. Więc jeśli jesteśmy na stronie Product:show i id: 123, link do this przekaże również ten parametr.

Oczywiście można parametry specyfikować bezpośrednio:

<a n:href="this refresh: 1">odśwież</a>

Funkcja isLinkCurrent() sprawdza, czy cel linku jest zgodny z aktualną stroną. Można tego użyć na przykład w szablonie do odróżnienia linków itp.

Parametry są takie same jak w metodzie link(), dodatkowo jednak można zamiast konkretnej akcji podać symbol wieloznaczny *, który oznacza dowolną akcję danego presentera.

{if !isLinkCurrent('Admin:login')}
	<a n:href="Admin:login">Zaloguj się</a>
{/if}

<li n:class="isLinkCurrent('Product:*') ? active">
	<a n:href="Product:">...</a>
</li>

W połączeniu z n:href w jednym elemencie można użyć skróconej formy:

<a n:class="isLinkCurrent() ? active" n:href="Home:">...</a>

Symbol wieloznaczny * można użyć tylko zamiast akcji, a nie presentera.

Aby sprawdzić, czy jesteśmy w określonym module lub jego podmodule, użyjemy metody isModuleCurrent(moduleName).

<li n:class="isModuleCurrent('Forum:Users') ? active">
	<a n:href="Product:">...</a>
</li>

Linki do sygnału

Celem linku nie musi być tylko presenter i akcja, ale także sygnał (wywołują metodę handle<Signal>()). Wtedy składnia jest następująca:

[//] [sub-component:]signal! [#fragment]

Sygnał odróżnia więc wykrzyknik:

<a n:href="click!">sygnał</a>

Można również utworzyć link do sygnału podkomponentu (lub pod-podkomponentu):

<a n:href="componentName:click!">sygnał</a>

Linki w komponencie

Ponieważ komponenty są samodzielnymi jednostkami wielokrotnego użytku, które nie powinny mieć żadnych powiązań z otaczającymi presenterami, linki działają tu trochę inaczej. Atrybut Latte n:href i znacznik {link} oraz metody komponentu takie jak link() i inne uważają cel linku zawsze za nazwę sygnału. Dlatego nie jest nawet konieczne podawanie wykrzyknika:

<a n:href="click">sygnał, a nie akcja</a>

Jeśli chcielibyśmy w szablonie komponentu linkować do presenterów, użyjemy do tego znacznika {plink}:

<a href={plink Home:default}>główna</a>

lub w kodzie

$this->getPresenter()->link('Home:default')

Aliasy

Czasami może się przydać przypisanie parze Presenter:akcja łatwo zapamiętywalnego aliasu. Na przykład stronę główną Front:Home:default nazwać po prostu home lub Admin:Dashboard:default jako admin.

Aliasy definiuje się w konfiguracji pod kluczem application › aliases:

application:
    aliases:
        home: Front:Home:default
        admin: Admin:Dashboard:default
        sign: Front:Sign:in

W linkach zapisuje się je za pomocą znaku @, na przykład:

<a n:href="@admin">administracja</a>

Są one obsługiwane również we wszystkich metodach pracujących z linkami, takich jak redirect() i podobnych.

Nieprawidłowe linki

Może się zdarzyć, że utworzymy nieprawidłowy link – albo dlatego, że prowadzi do nieistniejącego presentera, albo dlatego, że przekazuje więcej parametrów, niż akceptuje metoda docelowa w swojej sygnaturze, albo gdy dla akcji docelowej nie można wygenerować URL. Sposób postępowania z nieprawidłowymi linkami określa zmienna statyczna Presenter::$invalidLinkMode. Może ona przyjmować kombinację tych wartości (stałych):

  • Presenter::InvalidLinkSilent – tryb cichy, jako URL zwracany jest znak #
  • Presenter::InvalidLinkWarning – zgłaszane jest ostrzeżenie E_USER_WARNING, które w trybie produkcyjnym zostanie zalogowane, ale nie spowoduje przerwania działania skryptu
  • Presenter::InvalidLinkTextual – ostrzeżenie wizualne, wypisuje błąd bezpośrednio w linku
  • Presenter::InvalidLinkException – rzucany jest wyjątek InvalidLinkException

Domyślne ustawienie to InvalidLinkWarning w trybie produkcyjnym i InvalidLinkWarning | InvalidLinkTextual w trybie deweloperskim. InvalidLinkWarning w środowisku produkcyjnym nie powoduje przerwania skryptu, ale ostrzeżenie zostanie zalogowane. W środowisku deweloperskim zostanie przechwycone przez Tracy i wyświetli bluescreen. InvalidLinkTextual działa tak, że jako URL zwraca komunikat błędu zaczynający się od znaków #error:. Aby takie linki były od razu widoczne, dodajmy do CSS:

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

Jeśli nie chcemy, aby w środowisku deweloperskim generowane były ostrzeżenia, możemy ustawić tryb cichy bezpośrednio w konfiguracji.

application:
	silentLinks: true

LinkGenerator

Jak tworzyć linki z podobnym komfortem jak metoda link(), ale bez obecności presentera? Do tego służy Nette\Application\LinkGenerator.

LinkGenerator to usługa, którą można sobie przekazać przez konstruktor, a następnie tworzyć linki za pomocą jej metody link().

W porównaniu do presenterów jest tu różnica. LinkGenerator tworzy wszystkie linki od razu jako absolutne URL. Ponadto nie istnieje żaden “aktualny presenter”, więc nie można jako celu podać tylko nazwy akcji link('default') ani podawać ścieżek względnych do modułów.

Nieprawidłowe linki zawsze rzucają Nette\Application\UI\InvalidLinkException.

wersja: 4.0