Nette Documentation Preview

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

<div class=perex>

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

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

</div>


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


В шаблоне презентера .[#toc-in-the-presenter-template]
======================================================

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

```latte
<a n:href="Product:show">подробнее</a>
```

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

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

```latte
<a n:href="Product:show $product->id, $product->slug">подробнее</a>
```

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

```latte
<a n:href="Product:show $product->id, lang: en">подробнее</a>
```

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

Если параметры хранятся в массиве, их можно расширить с помощью оператора `(expand)` (что-то вроде оператора `...` в PHP, но работает с ассоциативными массивами):

```latte
{var $args = [$product->id, lang => en]}
<a n:href="Product:show (expand) $args">подробнее</a>
```

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

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

```latte
URL: {link Home:default}
```


В коде .[#toc-in-the-code]
==========================

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

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

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

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

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


Ссылки на презентер .[#toc-links-to-presenter]
==============================================

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

```
[//] [[[[:]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>
```

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

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

Особым случаем является [ссылка на себя|#Link-to-Current-Page]. Здесь мы напишем `this` в качестве цели.

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

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

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


Абсолютные пути .[#toc-absolute-paths]
======================================

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

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


Ссылка на текущую страницу .[#toc-link-to-current-page]
=======================================================

Цель `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 !$presenter->isLinkCurrent('Admin:login')}
	<a n:href="Admin:login">Войти</a>
{/if}

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

Сокращенная форма может использоваться в сочетании с `n:href` в одном элементе:

```latte
<a n:class="$presenter->isLinkCurrent() ? active" n:href="Product:detail">...</a>
```

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

Чтобы узнать, находимся ли мы в определенном модуле или его подмодуле, мы можем использовать метод `$presenter->isModuleCurrent(moduleName)`.

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


Ссылки на сигнал .[#toc-links-to-signal]
========================================

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

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

Поэтому сигнал выделяется восклицательным знаком:

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

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

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


Ссылки на компонент .[#toc-links-in-component]
==============================================

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

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

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

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

or in the code

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


Недействительные ссылки .[#toc-invalid-links]
=============================================

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

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

По умолчанию в рабочем режиме используется параметр `InvalidLinkWarning`, а в режиме разработки — `InvalidLinkWarning | InvalidLinkTextual`. `InvalidLinkWarning` не убивает сценарий в рабочей среде, но предупреждение будет зарегистрировано в журнале. В среде разработки [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:attribute n:href. Его значением является не URL, как вы привыкли видеть в атрибуте href, а имя презентера и действие.

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

<a n:href="Product:show $product->id, $product->slug">подробнее</a>

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

<a n:href="Product:show $product->id, lang: en">подробнее</a>

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

Если параметры хранятся в массиве, их можно расширить с помощью оператора (expand) (что-то вроде оператора ... в PHP, но работает с ассоциативными массивами):

{var $args = [$product->id, lang => en]}
<a n:href="Product:show (expand) $args">подробнее</a>

Так называемые постоянные параметры также автоматически передаются в ссылках.

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

URL: {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">refresh</a>

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

<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 !$presenter->isLinkCurrent('Admin:login')}
	<a n:href="Admin:login">Войти</a>
{/if}

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

Сокращенная форма может использоваться в сочетании с n:href в одном элементе:

<a n:class="$presenter->isLinkCurrent() ? active" n:href="Product:detail">...</a>

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

Чтобы узнать, находимся ли мы в определенном модуле или его подмодуле, мы можем использовать метод $presenter->isModuleCurrent(moduleName).

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

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

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

Поэтому сигнал выделяется восклицательным знаком:

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

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

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

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

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

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

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

or in the code

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

Может случиться так, что мы создадим некорректную ссылку — либо потому, что она ссылается на несуществующий презентер, либо потому, что она передает больше параметров, чем целевой метод получает в своей сигнатуре, либо когда не может быть сгенерирован 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(), но без презентера? Для этого у нас есть Nette\Application\LinkGenerator.

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

Есть разница по сравнению с презентерами. LinkGenerator создает все ссылки как абсолютные URL-адреса. Кроме того, нет «текущего презентера», поэтому невозможно указать только имя действия ‚link('default‘)' или относительные пути к модулям.

Недопустимые ссылки всегда выбросывают исключение Nette\Application\UI\InvalidLinkException.