Створення URL-посилань
Створювати посилання в Nette просто, як показувати пальцем. Достатньо лише вказати напрямок, і фреймворк зробить усю роботу за вас. Ми покажемо:
- як створювати посилання в шаблонах та інших місцях
- як відрізнити посилання на поточну сторінку
- що робити з недійсними посиланнями
Завдяки двосторонньому роутингу вам ніколи не доведеться вписувати URL-адреси вашого застосунку вручну в шаблони чи код, оскільки вони можуть згодом змінитися, або складно їх складати. У посиланні достатньо вказати presenter та дію, передати можливі параметри, і фреймворк сам згенерує URL. Власне, це дуже схоже на виклик функції. Вам це сподобається.
У шаблоні presenter'а
Найчастіше ми створюємо посилання в шаблонах, і чудовим помічником є
атрибут n:href
:
<a n:href="Product:show">деталі</a>
Зверніть увагу, що замість HTML-атрибута href
ми використали n:атрибут n:href
. Його значенням є
не URL, як це було б у випадку атрибута href
, а назва presenter'а та дії.
Натискання на посилання, спрощено кажучи, схоже на виклик методу
ProductPresenter::renderShow()
. І якщо він має параметри у своїй сигнатурі, ми
можемо викликати його з аргументами:
<a n:href="Product:show $product->id, $product->slug">деталі продукту</a>
Можна передавати й іменовані параметри. Наступне посилання передає
параметр lang
зі значенням cs
:
<a n:href="Product:show $product->id, lang: cs">деталі продукту</a>
Якщо метод ProductPresenter::renderShow()
не має $lang
у своїй
сигнатурі, він може отримати значення параметра за допомогою
$lang = $this->getParameter('lang')
або з властивості.
Якщо параметри зберігаються в масиві, їх можна розгорнути оператором
...
(в Latte 2.x оператором (expand)
):
{var $args = [$product->id, lang => cs]}
<a n:href="Product:show ...$args">деталі продукту</a>
У посиланнях також автоматично передаються так звані персистентні параметри.
Атрибут n:href
дуже зручний для HTML-тегів <a>
. Якщо ми
хочемо вивести посилання в іншому місці, наприклад, у тексті,
використовуємо {link}
:
Адреса: {link Home:default}
У коді
Для створення посилання в presenter'і служить метод link()
:
$url = $this->link('Product:show', $product->id);
Параметри можна передати також за допомогою масиву, де можна вказати й іменовані параметри:
$url = $this->link('Product:show', [$product->id, 'lang' => 'cs']);
Посилання можна створювати і без presenter'а, для цього існує LinkGenerator та його метод link()
.
Посилання на presenter
Якщо ціллю посилання є presenter та дія, воно має такий синтаксис:
[//] [[[[:]module:]presenter:]action | this] [#fragment]
Формат підтримують усі теги Latte та всі методи presenter'а, які працюють з
посиланнями, тобто n:href
, {link}
, {plink}
, link()
,
lazyLink()
, isLinkCurrent()
, redirect()
, redirectPermanent()
,
forward()
, canonicalize()
, а також LinkGenerator. Тому,
хоча в прикладах використано n:href
, там могла б бути будь-яка з
функцій.
Основною формою є Presenter:action
:
<a n:href="Home:default">головна сторінка</a>
Якщо ми посилаємося на дію поточного presenter'а, ми можемо опустити його назву:
<a n:href="default">головна сторінка</a>
Якщо ціллю є дія default
, ми можемо її опустити, але двокрапка має
залишитися:
<a n:href="Home:">головна сторінка</a>
Посилання також можуть вказувати на інші модулі. Тут
посилання розрізняються на відносні до вкладеного підмодуля або
абсолютні. Принцип аналогічний до шляхів на диску, тільки замість
слешів використовуються двокрапки. Припустимо, що поточний presenter є
частиною модуля Front
, тоді запишемо:
<a n:href="Shop:Product:show">посилання на Front:Shop:Product:show</a>
<a n:href=":Admin:Product:show">посилання на Admin:Product:show</a>
Особливим випадком є посилання на себе, коли
як ціль вказуємо this
.
<a n:href="this">оновити</a>
Ми можемо посилатися на певну частину сторінки через так званий
фрагмент за знаком решітки #
:
<a n:href="Home:#main">посилання на Home:default та фрагмент #main</a>
Абсолютні шляхи
Посилання, згенеровані за допомогою link()
або n:href
, завжди
є абсолютними шляхами (тобто починаються зі знака /
), але не
абсолютними URL з протоколом та доменом, як https://domain
.
Для генерації абсолютного URL додайте на початок два слеші (наприклад,
n:href="//Home:"
). Або можна перемкнути presenter, щоб він генерував лише
абсолютні посилання, встановивши $this->absoluteUrls = true
.
Посилання на поточну сторінку
Ціль this
створить посилання на поточну сторінку:
<a n:href="this">оновити</a>
Водночас передаються всі параметри, зазначені в сигнатурі методу
action<Action>()
або render<View>()
, якщо action<Action>()
не
визначено. Отже, якщо ми на сторінці Product:show
і id: 123
,
посилання на this
передасть і цей параметр.
Звичайно, можна вказати параметри безпосередньо:
<a n:href="this refresh: 1">оновити</a>
Функція isLinkCurrent()
перевіряє, чи ціль посилання збігається з
поточною сторінкою. Це можна використати, наприклад, у шаблоні для
розрізнення посилань тощо.
Параметри такі ж, як у методі link()
, але додатково можна замість
конкретної дії вказати заступний знак *
, який означає будь-яку
дію даного presenter'а.
{if !isLinkCurrent('Admin:login')}
<a n:href="Admin:login">Увійдіть</a>
{/if}
<li n:class="isLinkCurrent('Product:*') ? active">
<a n:href="Product:">...</a>
</li>
У комбінації з n:href
в одному елементі можна використовувати
скорочену форму:
<a n:class="isLinkCurrent() ? active" n:href="Home:">...</a>
Заступний знак *
можна використовувати лише замість дії, а не
presenter'а.
Для перевірки, чи ми знаходимося в певному модулі або його підмодулі,
використовуємо метод isModuleCurrent(moduleName)
.
<li n:class="isModuleCurrent('Forum:Users') ? active">
<a n:href="Product:">...</a>
</li>
Посилання на сигнал
Ціллю посилання може бути не тільки presenter та дія, але й сигнал (викликають метод
handle<Signal>()
). Тоді синтаксис такий:
[//] [sub-component:]signal! [#fragment]
Сигнал, отже, відрізняється знаком оклику:
<a n:href="click!">сигнал</a>
Можна створити й посилання на сигнал підкомпонента (або під-підкомпонента):
<a n:href="componentName:click!">сигнал</a>
Посилання в компоненті
Оскільки компоненти є окремими
повторно використовуваними одиницями, які не повинні мати жодних
зв'язків з навколишніми presenter'ами, посилання тут працюють трохи інакше.
Атрибут Latte n:href
та тег {link}
, а також методи компонента,
такі як link()
та інші, розглядають ціль посилання завжди як
назву сигналу. Тому навіть не потрібно вказувати знак оклику:
<a n:href="click">сигнал, а не дія</a>
Якщо ми хочемо в шаблоні компонента посилатися на presenter'ів,
використовуємо для цього тег {plink}
:
<a href={plink Home:default}>вступ</a>
або в коді
$this->getPresenter()->link('Home:default')
Аліаси
Іноді може бути корисно призначити парі Presenter:дія легко
запам'ятовуваний псевдонім. Наприклад, головну сторінку
Front:Home:default
назвати просто home
або Admin:Dashboard:default
як
admin
.
Аліаси визначаються в конфігурації під ключем
application › aliases
:
application:
aliases:
home: Front:Home:default
admin: Admin:Dashboard:default
sign: Front:Sign:in
У посиланнях вони потім записуються за допомогою символу @, наприклад:
<a n:href="@admin">адміністрація</a>
Вони також підтримуються у всіх методах, що працюють з посиланнями,
таких як redirect()
тощо.
Недійсні посилання
Може статися, що ми створимо недійсне посилання – або тому, що воно
веде на неіснуючий presenter, або тому, що передає більше параметрів, ніж
цільовий метод приймає у своїй сигнатурі, або коли для цільової дії
неможливо згенерувати URL. Як поводитися з недійсними посиланнями,
визначає статична змінна Presenter::$invalidLinkMode
. Вона може набувати
комбінації таких значень (констант):
Presenter::InvalidLinkSilent
– тихий режим, як URL повертається знак #Presenter::InvalidLinkWarning
– викидається попередження E_USER_WARNING, яке в робочому режимі буде залоговано, але не спричинить переривання виконання скриптаPresenter::InvalidLinkTextual
– візуальне попередження, виводить помилку безпосередньо в посиланніPresenter::InvalidLinkException
– викидається виняток InvalidLinkException
Стандартне налаштування — InvalidLinkWarning
у робочому режимі та
InvalidLinkWarning | InvalidLinkTextual
у режимі розробки. InvalidLinkWarning
у
робочому середовищі не спричиняє переривання скрипта, але
попередження буде залоговано. У середовищі розробки його перехопить Tracy і відобразить блюскрін. InvalidLinkTextual
працює так, що як URL повертає повідомлення про помилку, яке починається
символами #error:
. Щоб такі посилання були помітні з першого
погляду, доповнимо CSS:
a[href^="#error:"] {
background: red;
color: white;
}
Якщо ми не хочемо, щоб у середовищі розробки генерувалися попередження, можемо встановити тихий режим безпосередньо в конфігурації.
application:
silentLinks: true
LinkGenerator
Як створювати посилання з такою ж зручністю, як метод link()
, але
без наявності presenter'а? Для цього існує Nette\Application\LinkGenerator.
LinkGenerator — це сервіс, який ви можете отримати через конструктор, а
потім створювати посилання його методом link()
.
Порівняно з presenter'ами є відмінність. LinkGenerator створює всі посилання
одразу як абсолютні URL. Також не існує “поточного presenter'а”, тому не
можна як ціль вказати лише назву дії link('default')
або вказувати
відносні шляхи до модулів.
Недійсні посилання завжди викидають Nette\Application\UI\InvalidLinkException
.