forked from nette/docs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcreating-links.texy
262 lines (167 loc) · 9.47 KB
/
creating-links.texy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
Vytváření odkazů URL
********************
<div class=perex>
Tvořit odkazy v Nette je jednoduché, jako ukazovat prstem. Stačí jen namířit a framework už za vás všechnu práci udělá. Ukážeme si:
- jak vytvářet odkazy v šablonách i jinde
- jak odlišit odkaz na aktuální stránku
- co s neplatnými odkazy
</div>
Díky [obousměrnému routování |routing] nebudete nikdy muset do šablon či kódu zapisovat navrdo URL adresy vaší aplikace, které se mohou později měnit, nebo je komplikovaně skládat. V odkazu stačí uvést presenter a akci, předat případné parametry a framework už URL vygeneruje sám. Vlastně je to velice podobné, jako když voláte funkci. To se vám bude líbit.
V šabloně presenteru
====================
Nejčastěji vytváříme odkazy v šablonách a skvělým pomocníkem je atribut `n:href`:
```latte
<a n:href="Product:show">detail</a>
```
Všimněte si, že místo HTML atributu `href` jsme použili [n:atribut |latte:syntax#n-atributy] `n:href`. Jeho hodnotou pak není URL, jak by tomu bylo v případě atributu `href`, ale název presenteru a akce.
Kliknutí na odkaz je, zjednodušeně řečeno, něco jako zavolání metody `ProductPresenter::renderShow()`. A pokud má ve své signatuře parametry, můžeme ji volat s argumenty:
```latte
<a n:href="Product:show $product->id, $product->slug">detail produktu</a>
```
Je možné předávat i pojmenované parametry. Následující odkaz předává parametr `lang` s hodnotou `cs`:
```latte
<a n:href="Product:show $product->id, lang: cs">detail produktu</a>
```
Pokud metoda `ProductPresenter::renderShow()` nemá `$lang` ve své signatuře, může si hodnotu parametru zjistit pomocí `$lang = $this->getParameter('lang')`.
Pokud jsou parametry uložené v poli, lze je rozvinout operátorem `...` (v Latte 2.x operátorem `(expand)`):
```latte
{var $args = [$product->id, lang => cs]}
<a n:href="Product:show ...$args">detail produktu</a>
```
V odkazech se také automaticky předávají tzv. [persistentní parametry|presenters#persistentní parametry].
Atribut `n:href` je velmi šikovný pro HTML značky `<a>`. Chceme-li odkaz vypsat jinde, například v textu, použijeme `{link}`:
```latte
Adresa je: {link Home:default}
```
V kódu
======
K vytvoření odkazu v presenteru slouží metoda `link()`:
```php
$url = $this->link('Product:show', $product->id);
```
Parametry lze předat také pomocí pole, kde lze uvést i pojmenované parametry:
```php
$url = $this->link('Product:show', [$product->id, 'lang' => 'cs']);
```
Odkazy lze vytvářet i bez presenteru, od toho je tu [#LinkGenerator] a jeho metoda `link()`.
Odkazy na presenter
===================
Pokud je cílem odkazu presenter a akce, má tuto syntaxi:
```
[//] [[[[:]module:]presenter:]action | this] [#fragment]
```
Formát podporují všechny značky Latte a všechny metody presenteru, které s odkazy pracují, tedy `n:href`, `{link}`, `{plink}`, `link()`, `lazyLink()`, `isLinkCurrent()`, `redirect()`, `redirectPermanent()`, `forward()`, `canonicalize()` a také [#LinkGenerator]. Takže i když je v příkladech použit `n:href`, mohla by tam být kterákoliv z funkcí.
Základním tvarem je tedy `Presenter:action`:
```latte
<a n:href="Home:default">úvodní stránka</a>
```
Pokud odkazujeme na akci aktuálního presenteru, můžeme jeho název vynechat:
```latte
<a n:href="default">úvodní stránka</a>
```
Pokud je cílem akce `default`, můžeme ji vynechat, ale dvojtečka musí zůstat:
```latte
<a n:href="Home:">úvodní stránka</a>
```
Odkazy mohou také směřovat do jiných [modulů |modules]. Zde se odkazy rozlišují na relativní do zanořeného submodulu, nebo absolutní. Princip je analogický k cestám na disku, jen místo lomítek jsou dvojtečky. Předpokládejme, že aktuální presenter je součástí modulu `Front`, potom zapíšeme:
```latte
<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>
```
Speciálním případem je odkaz [na sebe sama|#Odkaz na aktuální stránku], kdy jako cíl uvedeme `this`.
```latte
<a n:href="this">refresh</a>
```
Odkazovat můžeme na určitou část stránky přes tzv. fragment za znakem mřížky `#`:
```latte
<a n:href="Home:#main">odkaz na Home:default a fragment #main</a>
```
Absolutní cesty
===============
Odkazy generované pomocí `link()` nebo `n:href` jsou vždy absolutní cesty (tj. začínají znakem `/`), ale nikoliv absolutní URL s protokolem a doménou jako `https://domain`.
Pro vygenerování absolutní URL přidejte na začátek dvě lomítka (např. `n:href="//Home:"`). Nebo lze přepnout presenter, aby generoval jen absolutní odkazy nastavením `$this->absoluteUrls = true`.
Odkaz na aktuální stránku
=========================
Cíl `this` vytvoří odkaz na aktuální stránku:
```latte
<a n:href="this">refresh</a>
```
Zároveň se přenáší i všechny parametry uvedené v signatuře `render<View>()` nebo `action<Action>()` metody. Takže pokud jsme na stránce `Product:show` a `id: 123`, odkaz na `this` předá i tento parameter.
Samozřejmě je možné parametry specifikovat přímo:
```latte
<a n:href="this refresh: 1">refresh</a>
```
Funkce `isLinkCurrent()` zjišťuje, zda je cíl odkazu shodný s aktuální stránkou. Toho lze využít například v šabloně k odlišení odkazů apod.
Parametry jsou stejné jako u metody `link()`, navíc je však možné místo konkrétní akce uvést zástupný znak `*`, který znamená jakoukoliv akci daného presenteru.
```latte
{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>
```
V kombinaci s `n:href` v jednom elementu se dá použít zkrácená podoba:
```latte
<a n:class="isLinkCurrent() ? active" n:href="Home:">...</a>
```
Zástupný znak `*` lze použít pouze místo akce, nikoliv presenteru.
Pro zjištění, zda jsme v určitém modulu nebo jeho submodulu, použijeme metodu `isModuleCurrent(moduleName)`.
```latte
<li n:class="isModuleCurrent('Forum:Users') ? active">
<a n:href="Product:">...</a>
</li>
```
Odkazy na signál
================
Cílem odkazu nemusí být jen presenter a akce, ale také [signál|components#Signál] (volají metodu `handle<Signal>()`). Pak je syntaxe následující:
```
[//] [sub-component:]signal! [#fragment]
```
Signál tedy odlišuje vykřičník:
```latte
<a n:href="click!">signal</a>
```
Lze vytvořit i odkaz na signál subkomponenty (nebo sub-subkomponenty):
```latte
<a n:href="componentName:click!">signal</a>
```
Odkazy v komponentě
===================
Protože [komponenty|components] jsou samostatné znovupoužitelné celky, které by neměly mít žádné vazby na okolní presentery, fungují tu odkazy trošku jinak. Atribut Latte `n:href` a značka `{link}` i metody komponent jako je `link()` a další považují cíl odkazu **vždy za název signálu**. Proto není nutné ani uvádět vykřičník:
```latte
<a n:href="click">signál, nikoliv akce</a>
```
Pokud bychom chtěli v šabloně komponenty odkazovat na presentery, použijeme k tomu značku `{plink}`:
```latte
<a href="{plink Home:default}">úvod</a>
```
nebo v kódu
```php
$this->getPresenter()->link('Home:default')
```
Neplatné odkazy
===============
Může se stát, že vytvoříme neplatný odkaz - buď proto, že vede na neexistující presenter, nebo proto, že předává víc parametrů, než které cílová metoda přijímá ve své signatuře, nebo když pro cílovou akci nelze vygenerovat URL. Jak naložit s neplatnými odkazy určuje statická proměnná `Presenter::$invalidLinkMode`. Ta může nabývat kombinaci těchto hodnot (konstant):
- `Presenter::InvalidLinkSilent` - tichý režim, jako URL se vrátí znak #
- `Presenter::InvalidLinkWarning` - vyhodí se varování E_USER_WARNING, které bude v produkčním režimu zalogováno, ale nezpůsobí přerušení běhu skriptu
- `Presenter::InvalidLinkTextual` - vizuální varování, vypíše chybu přímo do odkazu
- `Presenter::InvalidLinkException` - vyhodí se výjimka InvalidLinkException
Výchozí nastavení je `InvalidLinkWarning` v produkčním režimu a `InvalidLinkWarning | InvalidLinkTextual` ve vývojovém. `InvalidLinkWarning` v produkčním prostředí nezpůsobí přerušení skriptu, ale varování bude zalogováno. Ve vývojovém prostředí ho zachytí [Tracy |tracy:] a zobrazí bluescreen. `InvalidLinkTextual` pracuje tak, že jako URL vrátí chybovou zprávu, která začíná znaky `#error:`. Aby takové odkazy byly na první pohled patrné, doplníme si do CSS:
```css
a[href^="#error:"] {
background: red;
color: white;
}
```
Pokud nechceme, aby se ve vývojovém prostředí produkovala varování, můžeme nastavit tichý režim přímo v [konfiguraci|configuration].
```neon
application:
silentLinks: true
```
LinkGenerator
=============
Jak vytvářet odkazy s podobným komfortem jako má metoda `link()`, ale bez přítomnosti presenteru? Od toho je tu [api:Nette\Application\LinkGenerator].
LinkGenerátor je služba, kterou si můžete nechat předat přes konstruktor a poté vytvářet odkazy jeho metodou `link()`.
Oproti presenterům je tu rozdíl. LinkGenerator vytváří všechny odkazy rovnou jako absolutní URL. A dále neexistuje žádný "aktuální presenter", takže nelze jako cíl uvést jen název akce `link('default')` nebo uvádět relativní cesty k [modulům |modules].
Neplatné odkazy vždy vyhazují `Nette\Application\UI\InvalidLinkException`.