Nette Documentation Preview

syntax
Создание URL-ссылок
*******************

<div class=perex>

Создавать ссылки в Nette просто, как указывать пальцем. Достаточно просто направить, и фреймворк уже сделает всю работу за вас. Мы покажем:

- как создавать ссылки в шаблонах и в других местах
- как отличить ссылку на текущую страницу
- что делать с недействительными ссылками

</div>


Благодаря [двусторонней маршрутизации |routing] вам никогда не придется жестко прописывать URL-адреса вашего приложения в шаблонах или коде, которые могут позже измениться, или сложно их составлять. В ссылке достаточно указать презентер и действие, передать возможные параметры, и фреймворк сам сгенерирует URL. На самом деле, это очень похоже на вызов функции. Вам это понравится.


В шаблоне презентера
====================

Чаще всего мы создаем ссылки в шаблонах, и отличным помощником является атрибут `n:href`:

```latte
<a n:href="Product:show">деталь</a>
```

Обратите внимание, что вместо HTML-атрибута `href` мы использовали [n:атрибут |latte:syntax#n:атрибуты] `n:href`. Его значением является не URL, как это было бы в случае атрибута `href`, а имя презентера и действия.

Нажатие на ссылку, упрощенно говоря, похоже на вызов метода `ProductPresenter::renderShow()`. И если у него в сигнатуре есть параметры, мы можем вызвать его с аргументами:

```latte
<a n:href="Product:show $product->id, $product->slug">деталь продукта</a>
```

Можно передавать и именованные параметры. Следующая ссылка передает параметр `lang` со значением `cs`:

```latte
<a n:href="Product:show $product->id, lang: cs">деталь продукта</a>
```

Если метод `ProductPresenter::renderShow()` не имеет `$lang` в своей сигнатуре, он может получить значение параметра с помощью `$lang = $this->getParameter('lang')` или из [свойства |presenters#Параметры запроса].

Если параметры хранятся в массиве, их можно развернуть с помощью оператора `...` (в Latte 2.x оператором `(expand)`):

```latte
{var $args = [$product->id, lang => cs]}
<a n:href="Product:show ...$args">деталь продукта</a>
```

В ссылках также автоматически передаются так называемые [персистентные параметры |presenters#Персистентные параметры].

Атрибут `n:href` очень удобен для HTML-тегов `<a>`. Если мы хотим вывести ссылку в другом месте, например, в тексте, используем `{link}`:

```latte
Адрес: {link Home:default}
```


В коде
======

Для создания ссылки в презентере служит метод `link()`:

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

Параметры можно передать также с помощью массива, где можно указать и именованные параметры:

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

Ссылки можно создавать и без презентера, для этого есть [#LinkGenerator] и его метод `link()`.


Ссылки на презентер
===================

Если целью ссылки является презентер и действие, используется следующий синтаксис:

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

Формат поддерживается всеми тегами Latte и всеми методами презентера, работающими со ссылками, то есть `n:href`, `{link}`, `{plink}`, `link()`, `lazyLink()`, `isLinkCurrent()`, `redirect()`, `redirectPermanent()`, `forward()`, `canonicalize()`, а также [#LinkGenerator]. Так что, хотя в примерах используется `n:href`, там могла бы быть любая из этих функций.

Основной формой является `Presenter:action`:

```latte
<a n:href="Home:default">главная страница</a>
```

Если мы ссылаемся на действие текущего презентера, мы можем опустить его имя:

```latte
<a n:href="default">главная страница</a>
```

Если целью является действие `default`, мы можем его опустить, но двоеточие должно остаться:

```latte
<a n:href="Home:">главная страница</a>
```

Ссылки также могут указывать на другие [модули |directory-structure#Презентеры и шаблоны]. Здесь ссылки делятся на относительные к вложенному подмодулю или абсолютные. Принцип аналогичен путям на диске, только вместо слешей используются двоеточия. Предположим, что текущий презентер является частью модуля `Front`, тогда запишем:

```latte
<a n:href="Shop:Product:show">ссылка на Front:Shop:Product:show</a>
<a n:href=":Admin:Product:show">ссылка на Admin:Product:show</a>
```

Особым случаем является ссылка [на себя |#Ссылка на текущую страницу], когда в качестве цели указываем `this`.

```latte
<a n:href="this">обновить</a>
```

Мы можем ссылаться на определенную часть страницы через так называемый фрагмент после символа решетки `#`:

```latte
<a n:href="Home:#main">ссылка на Home:default и фрагмент #main</a>
```


Абсолютные пути
===============

Ссылки, генерируемые с помощью `link()` или `n:href`, всегда являются абсолютными путями (т. е. начинаются с символа `/`), но не абсолютными URL с протоколом и доменом, как `https://domain`.

Для генерации абсолютного URL добавьте в начало два слеша (например, `n:href="//Home:"`). Или можно переключить презентер, чтобы он генерировал только абсолютные ссылки, установив `$this->absoluteUrls = true`.


Ссылка на текущую страницу
==========================

Цель `this` создаст ссылку на текущую страницу:

```latte
<a n:href="this">обновить</a>
```

При этом передаются все параметры, указанные в сигнатуре метода `action<Action>()` или `render<View>()`, если `action<Action>()` не определена. Так что если мы находимся на странице `Product:show` и `id: 123`, ссылка на `this` передаст и этот параметр.

Конечно, можно указать параметры напрямую:

```latte
<a n:href="this refresh: 1">обновить</a>
```

Функция `isLinkCurrent()` проверяет, совпадает ли цель ссылки с текущей страницей. Это можно использовать, например, в шаблоне для выделения ссылок и т. п.

Параметры такие же, как у метода `link()`, но дополнительно можно вместо конкретного действия указать подстановочный знак `*`, который означает любое действие данного презентера.

```latte
{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` в одном элементе можно использовать сокращенную форму:

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

Подстановочный знак `*` можно использовать только вместо действия, а не презентера.

Для проверки, находимся ли мы в определенном модуле или его подмодуле, используем метод `isModuleCurrent(moduleName)`.

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


Ссылки на сигнал
================

Целью ссылки может быть не только презентер и действие, но и [сигнал |components#Сигнал] (вызывают метод `handle<Signal>()`). Тогда синтаксис следующий:

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

Сигнал отличает восклицательный знак:

```latte
<a n:href="click!">сигнал</a>
```

Можно создать и ссылку на сигнал подкомпонента (или под-подкомпонента):

```latte
<a n:href="componentName:click!">сигнал</a>
```


Ссылки в компоненте
===================

Поскольку [компоненты |components] являются отдельными повторно используемыми единицами, которые не должны иметь никаких связей с окружающими презентерами, ссылки здесь работают немного иначе. Атрибут Latte `n:href` и тег `{link}`, а также методы компонента, такие как `link()` и другие, считают цель ссылки **всегда именем сигнала**. Поэтому не нужно даже указывать восклицательный знак:

```latte
<a n:href="click">сигнал, а не действие</a>
```

Если бы мы хотели в шаблоне компонента ссылаться на презентеры, мы бы использовали для этого тег `{plink}`:

```latte
<a href={plink Home:default}>введение</a>
```

или в коде

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


Псевдонимы .{data-version:v3.2.2}
=================================

Иногда может быть полезно присвоить паре Presenter:action легко запоминающийся псевдоним. Например, главную страницу `Front:Home:default` назвать просто `home` или `Admin:Dashboard:default` как `admin`.

Псевдонимы определяются в [конфигурации |configuration] под ключом `application › aliases`:

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

В ссылках они затем записываются с помощью символа @, например:

```latte
<a n:href="@admin">администрирование</a>
```

Они также поддерживаются во всех методах, работающих со ссылками, таких как `redirect()` и подобных.


Недействительные ссылки
=======================

Может случиться, что мы создадим недействительную ссылку — либо потому, что она ведет на несуществующий презентер, либо потому, что передает больше параметров, чем принимает целевой метод в своей сигнатуре, либо когда для целевого действия невозможно сгенерировать URL. Как обращаться с недействительными ссылками, определяет статическая переменная `Presenter::$invalidLinkMode`. Она может принимать комбинацию следующих значений (констант):

- `Presenter::InvalidLinkSilent` — тихий режим, в качестве URL возвращается символ #
- `Presenter::InvalidLinkWarning` — выбрасывается предупреждение E_USER_WARNING, которое в режиме production будет залогировано, но не вызовет прерывания выполнения скрипта
- `Presenter::InvalidLinkTextual` — визуальное предупреждение, выводит ошибку прямо в ссылку
- `Presenter::InvalidLinkException` — выбрасывается исключение InvalidLinkException

Настройка по умолчанию — `InvalidLinkWarning` в режиме production и `InvalidLinkWarning | InvalidLinkTextual` в режиме разработки. `InvalidLinkWarning` в production-среде не вызывает прерывания скрипта, но предупреждение будет залогировано. В среде разработки его перехватывает [Tracy |tracy:] и отображает синий экран. `InvalidLinkTextual` работает так, что в качестве URL возвращает сообщение об ошибке, которое начинается символами `#error:`. Чтобы такие ссылки были заметны с первого взгляда, добавим в CSS:

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

Если мы не хотим, чтобы в среде разработки генерировались предупреждения, мы можем установить тихий режим прямо в [конфигурации |configuration].

```neon
application:
	silentLinks: true
```


LinkGenerator
=============

Как создавать ссылки с таким же удобством, как у метода `link()`, но без присутствия презентера? Для этого существует [api:Nette\Application\LinkGenerator].

LinkGenerator — это сервис, который вы можете получить через конструктор и затем создавать ссылки его методом `link()`.

По сравнению с презентерами есть разница. LinkGenerator создает все ссылки сразу как абсолютные URL. И далее не существует "текущего презентера", поэтому нельзя в качестве цели указать только имя действия `link('default')` или указывать относительные пути к модулям.

Недействительные ссылки всегда выбрасывают `Nette\Application\UI\InvalidLinkException`.

Создание URL-ссылок

Создавать ссылки в Nette просто, как указывать пальцем. Достаточно просто направить, и фреймворк уже сделает всю работу за вас. Мы покажем:

  • как создавать ссылки в шаблонах и в других местах
  • как отличить ссылку на текущую страницу
  • что делать с недействительными ссылками

Благодаря двусторонней маршрутизации вам никогда не придется жестко прописывать URL-адреса вашего приложения в шаблонах или коде, которые могут позже измениться, или сложно их составлять. В ссылке достаточно указать презентер и действие, передать возможные параметры, и фреймворк сам сгенерирует URL. На самом деле, это очень похоже на вызов функции. Вам это понравится.

В шаблоне презентера

Чаще всего мы создаем ссылки в шаблонах, и отличным помощником является атрибут n:href:

<a n:href="Product:show">деталь</a>

Обратите внимание, что вместо HTML-атрибута href мы использовали n:атрибут n:href. Его значением является не URL, как это было бы в случае атрибута href, а имя презентера и действия.

Нажатие на ссылку, упрощенно говоря, похоже на вызов метода 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}

В коде

Для создания ссылки в презентере служит метод link():

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

Параметры можно передать также с помощью массива, где можно указать и именованные параметры:

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

Ссылки можно создавать и без презентера, для этого есть LinkGenerator и его метод link().

Ссылки на презентер

Если целью ссылки является презентер и действие, используется следующий синтаксис:

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

Формат поддерживается всеми тегами Latte и всеми методами презентера, работающими со ссылками, то есть n:href, {link}, {plink}, link(), lazyLink(), isLinkCurrent(), redirect(), redirectPermanent(), forward(), canonicalize(), а также LinkGenerator. Так что, хотя в примерах используется n:href, там могла бы быть любая из этих функций.

Основной формой является Presenter:action:

<a n:href="Home:default">главная страница</a>

Если мы ссылаемся на действие текущего презентера, мы можем опустить его имя:

<a n:href="default">главная страница</a>

Если целью является действие default, мы можем его опустить, но двоеточие должно остаться:

<a n:href="Home:">главная страница</a>

Ссылки также могут указывать на другие модули. Здесь ссылки делятся на относительные к вложенному подмодулю или абсолютные. Принцип аналогичен путям на диске, только вместо слешей используются двоеточия. Предположим, что текущий презентер является частью модуля 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:"). Или можно переключить презентер, чтобы он генерировал только абсолютные ссылки, установив $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(), но дополнительно можно вместо конкретного действия указать подстановочный знак *, который означает любое действие данного презентера.

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

Подстановочный знак * можно использовать только вместо действия, а не презентера.

Для проверки, находимся ли мы в определенном модуле или его подмодуле, используем метод isModuleCurrent(moduleName).

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

Ссылки на сигнал

Целью ссылки может быть не только презентер и действие, но и сигнал (вызывают метод handle<Signal>()). Тогда синтаксис следующий:

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

Сигнал отличает восклицательный знак:

<a n:href="click!">сигнал</a>

Можно создать и ссылку на сигнал подкомпонента (или под-подкомпонента):

<a n:href="componentName:click!">сигнал</a>

Ссылки в компоненте

Поскольку компоненты являются отдельными повторно используемыми единицами, которые не должны иметь никаких связей с окружающими презентерами, ссылки здесь работают немного иначе. Атрибут Latte n:href и тег {link}, а также методы компонента, такие как link() и другие, считают цель ссылки всегда именем сигнала. Поэтому не нужно даже указывать восклицательный знак:

<a n:href="click">сигнал, а не действие</a>

Если бы мы хотели в шаблоне компонента ссылаться на презентеры, мы бы использовали для этого тег {plink}:

<a href={plink Home:default}>введение</a>

или в коде

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

Псевдонимы

Иногда может быть полезно присвоить паре Presenter:action легко запоминающийся псевдоним. Например, главную страницу 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() и подобных.

Недействительные ссылки

Может случиться, что мы создадим недействительную ссылку — либо потому, что она ведет на несуществующий презентер, либо потому, что передает больше параметров, чем принимает целевой метод в своей сигнатуре, либо когда для целевого действия невозможно сгенерировать URL. Как обращаться с недействительными ссылками, определяет статическая переменная Presenter::$invalidLinkMode. Она может принимать комбинацию следующих значений (констант):

  • Presenter::InvalidLinkSilent — тихий режим, в качестве URL возвращается символ #
  • Presenter::InvalidLinkWarning — выбрасывается предупреждение E_USER_WARNING, которое в режиме production будет залогировано, но не вызовет прерывания выполнения скрипта
  • Presenter::InvalidLinkTextual — визуальное предупреждение, выводит ошибку прямо в ссылку
  • Presenter::InvalidLinkException — выбрасывается исключение InvalidLinkException

Настройка по умолчанию — InvalidLinkWarning в режиме production и InvalidLinkWarning | InvalidLinkTextual в режиме разработки. InvalidLinkWarning в production-среде не вызывает прерывания скрипта, но предупреждение будет залогировано. В среде разработки его перехватывает Tracy и отображает синий экран. InvalidLinkTextual работает так, что в качестве URL возвращает сообщение об ошибке, которое начинается символами #error:. Чтобы такие ссылки были заметны с первого взгляда, добавим в CSS:

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

Если мы не хотим, чтобы в среде разработки генерировались предупреждения, мы можем установить тихий режим прямо в конфигурации.

application:
	silentLinks: true

LinkGenerator

Как создавать ссылки с таким же удобством, как у метода link(), но без присутствия презентера? Для этого существует Nette\Application\LinkGenerator.

LinkGenerator — это сервис, который вы можете получить через конструктор и затем создавать ссылки его методом link().

По сравнению с презентерами есть разница. LinkGenerator создает все ссылки сразу как абсолютные URL. И далее не существует „текущего презентера“, поэтому нельзя в качестве цели указать только имя действия link('default') или указывать относительные пути к модулям.

Недействительные ссылки всегда выбрасывают Nette\Application\UI\InvalidLinkException.