Tworzenie linków URL

Tworzenie linków w Nette jest tak proste jak wskazanie palcem. Wystarczy wskazać, a framework wykona całą pracę za Ciebie. Zobaczmy:

  • jak tworzyć linki w szablonach i innych miejscach
  • jak wyróżnić link do bieżącej strony
  • co zrobić z nieważnymi linkami

Dzięki dwukierunkowemu routingowi nigdy nie będziesz musiał pisać adresów URL aplikacji w szablonach lub kodzie, który może się zmienić lub być skomplikowany do skomponowania później. Wystarczy określić prezentera i akcję w linku, przekazać dowolne parametry, a framework sam wygeneruje adres URL. W rzeczywistości jest to bardzo podobne do wywołania funkcji. Spodoba ci się to.

W szablonie prezentera

Najczęściej tworzymy linki w szablonach i dużą pomocą jest atrybut n:href:

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

Zauważ, że zamiast atrybutu HTML href użyliśmy atrybutu n: n:href. Jego wartością nie jest wtedy adres URL, jak miałoby to miejsce w przypadku atrybutu href, ale nazwa prezentera i akcja.

Kliknięcie na link jest, najprościej mówiąc, jak wywołanie metody ProductPresenter::renderShow(). A jeśli ma parametry w swoim podpisie, możemy go wywołać z argumentami:

<a n:href="Product:show $product->id, $product->slug">detail produktu</a>

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

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

Jeśli metoda ProductPresenter::renderShow() nie ma w swojej sygnaturze $lang, może pobrać 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ąć za pomocą operatora ... (w Latte 2.x operator (expand)):

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

Tak zwane trwałe parametry są również automatycznie przekazywane w referencjach.

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

Adresa je: {link Home:default}

W kodzie

Metoda link() służy do tworzenia linku w prezenterze:

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

Parametry mogą być również przekazywane za pomocą tablicy, gdzie można również określić parametry nazwane:

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

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

Jeśli celem linku jest prezenter i akcja, to ma on taką składnię:

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

Format jest obsługiwany przez wszystkie znaczniki Latte oraz wszystkie metody prezentera, które pracują z linkami, czyli n:href, {link}, {plink}, link(), lazyLink(), isLinkCurrent(), redirect(), redirectPermanent(), forward(), canonicalize() a także LinkGenerator. Więc nawet jeśli n:href jest używany w przykładach, każda z funkcji może tam być.

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

<a n:href="Home:default">úvodní stránka</a>

Jeśli odnosimy się do działania bieżącego prezentera, możemy pominąć nazwę prezentera:

<a n:href="default">úvodní stránka</a>

Jeśli celem działania jest default, możemy go pominąć, ale dwukropek musi pozostać:

<a n:href="Home:">úvodní stránka</a>

Linki mogą również wskazywać na inne moduły. Tutaj linki są rozróżniane jako względne do zagnieżdżonego podmodułu lub bezwzględne. Zasada działania jest analogiczna do ścieżek dyskowych, ale z dwukropkami zamiast ukośników. Załóżmy, że aktualny prezenter jest częścią modułu Front, wtedy piszemy:

<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>

Szczególnym przypadkiem jest autoreferencja, w której jako miejsce docelowe podajemy this.

<a n:href="this">refresh</a>

Możemy linkować do określonej części strony poprzez fragment po znaku siatki #:

<a n:href="Home:#main">odkaz na Home:default a fragment #main</a>

Ścieżki bezwzględne

Linki generowane przez link() lub n:href są zawsze ścieżkami bezwzględnymi (tj. zaczynają się od /), ale nie bezwzględnymi adresami URL z protokołem i domeną jak https://domain.

Aby wygenerować bezwzględny adres URL, dodaj dwa ukośniki na początku (np. n:href="//Home:"). Możesz też przełączyć prezenter, aby generował tylko bezwzględne linki, ustawiając $this->absoluteUrls = true.

Cel this tworzy link do bieżącej strony:

<a n:href="this">refresh</a>

Wszystkie parametry określone w podpisie są również przekazywane render<View>() lub action<Action>() metody. Jeśli więc jesteśmy na Product:show i id: 123, to link do this również przekaże ten parametr.

Oczywiście istnieje możliwość bezpośredniego podania parametrów:

<a n:href="this refresh: 1">refresh</a>

Funkcja isLinkCurrent() sprawdza, czy miejsce docelowe linku jest takie samo jak bieżąca strona. Można to wykorzystać np. w szablonie do wyróżnienia linków itp.

Parametry są takie same jak w przypadku metody link(), ale dodatkowo można zamiast konkretnej akcji podać symbol wieloznaczny *, aby wskazać dowolną akcję prezentera.

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

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

Forma krótka może być stosowana w połączeniu z n:href w jednym elemencie:

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

Symbol wieloznaczny * może być użyty tylko w miejsce akcji, nie prezentera.

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

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

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

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

Sygnał ten jest więc wyróżniony wykrzyknikiem:

<a n:href="click!">signal</a>

Można również utworzyć odniesienie do sygnału podrzędnego (lub podrzędnego):

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

Ponieważ komponenty są samodzielnymi, wielokrotnego użytku jednostkami, które nie powinny mieć żadnych powiązań z otaczającymi prezenterami, linki działają tutaj nieco inaczej. Atrybut Latte n:href oraz znacznik {link}, a także metody składowe, takie jak link() i inne, traktują cel łącza zawsze jako nazwę sygnału. Dlatego nie ma nawet potrzeby umieszczania wykrzyknika:

<a n:href="click">signál, nikoliv akce</a>

Gdybyśmy chcieli odwołać się do prezenterów w szablonie komponentu, użylibyśmy do tego celu tagu {plink}:

<a href="{plink Home:default}">úvod</a>

lub w kodzie

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

Może się zdarzyć, że utworzymy nieprawidłowy link – albo dlatego, że prowadzi do nieistniejącego prezentera, albo dlatego, że przekazuje więcej parametrów niż docelowa metoda akceptuje w swojej sygnaturze, albo gdy nie można wygenerować adresu URL dla docelowej akcji. O tym, jak obsłużyć nieprawidłowe linki, decyduje zmienna statyczna Presenter::$invalidLinkMode. Może przyjmować kombinację następujących wartości (stałych):

  • Presenter::InvalidLinkSilent – tryb cichy, adres URL zwróci znak #.
  • Presenter::InvalidLinkWarning – wyświetlane jest ostrzeżenie E_USER_WARNING, które będzie rejestrowane w trybie produkcyjnym, ale nie spowoduje przerwania skryptu
  • Presenter::InvalidLinkTextual – ostrzeżenie wizualne, drukuje błąd bezpośrednio do linku
  • Presenter::InvalidLinkException – rzuca wyjątek InvalidLinkException

Domyślnie jest to InvalidLinkWarning w trybie produkcyjnym i InvalidLinkWarning | InvalidLinkTextual w trybie deweloperskim. InvalidLinkWarning w trybie produkcyjnym nie spowoduje przerwania skryptu, ale ostrzeżenie zostanie zapisane w dzienniku. W środowisku programistycznym Tracy złapie to i wyświetli bluescreen. InvalidLinkTextual działa poprzez zwrócenie komunikatu o błędzie, który zaczyna się od #error: jako adresu URL. Aby takie linki były widoczne na pierwszy rzut oka, dodamy trochę CSS:

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

Jeśli nie chcemy, aby środowisko programistyczne generowało ostrzeżenia, możemy ustawić tryb silent bezpośrednio w konfiguracji.

application:
	silentLinks: true

LinkGenerator

Jak tworzyć linki z podobną wygodą jak metoda link(), ale bez obecności prezentera? Po to właśnie jest Nette\Application\LinkGenerator.

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

W porównaniu z prezenterami jest różnica. LinkGenerator tworzy wszystkie linki bezpośrednio jako bezwzględne adresy URL. Nie ma również “rzeczywistego prezentera”, więc nie możesz po prostu podać nazwy akcji link('default') jako celu lub podać względnych ścieżek do modułów.

Nieważne linki zawsze wyrzucają Nette\Application\UI\InvalidLinkException.

wersja: 4.0