Creating URL Links
Creating links in Nette is as easy as pointing a finger. Just point and the framework will do all the work for you. We will show:
- how to create links in templates and elsewhere
- how to distinguish a link to the current page
- what about invalid links
Thanks to bidirectional routing, you'll never have to hardcode application's URLs in the templates or code, which may change later or be complicated to compose. Just specify the presenter and the action in the link, pass any parameters and the framework will generate the URL itself. In fact, it's very similar to calling a function. You will like it.
In the Presenter Template
Most often we create links in templates and a great helper is the attribute n:href
:
<a n:href="Product:show">detail</a>
Note, that instead of the HTML attribute href
we've used n:attribute n:href
. Its value isn't a URL, as you are
used to with the href
attribute, but name of the presenter and the action.
Clicking on a link is, simply said, something like calling a method ProductPresenter::renderShow()
. And if it has
parameters in its signature, we can call it with arguments:
<a n:href="Product:show $product->id, $product->slug">detail</a>
It is also possible to pass named parameters. The following link passes parameter lang
with value
en
:
<a n:href="Product:show $product->id, lang => en">detail</a>
If the method ProductPresenter::renderShow()
does not have $lang
in its signature, it can retrieve
the value of the parameter using $lang = $this->getParameter('lang')
or from the property.
If the parameters are stored in an array, they can be expanded with the ...
operator (or (expand)
operator in Latte 2.x):
{var $args = [$product->id, lang => en]}
<a n:href="Product:show (expand) $args">detail</a>
The so-called persistent parameters are also automatically passed in the links.
Attribute n:href
is very handy for HTML tags <a>
. If we want to print the link elsewhere, for
example in the text, we use {link}
:
URL is: {link Home:default}
In the Code
The method link()
is used to create a link in the presenter:
$url = $this->link('Product:show', $product->id);
Parameters can also be passed as an array where named parameters can also be specified:
$url = $this->link('Product:show', [$product->id, 'lang' => 'cs']);
Links can be created without a presenter too, using the LinkGenerator and its method
link()
.
Links to Presenter
If the target of the link is presenter and action, it has this syntax:
[//] [[[[:]module:]presenter:]action | this] [#fragment]
The format is supported by all Latte tags and all presenter methods that work with links, ie n:href
,
{link}
, {plink}
, link()
, lazyLink()
, isLinkCurrent()
,
redirect()
, redirectPermanent()
, forward()
, canonicalize()
and also LinkGenerator. So even if n:href
is used in the examples, there could be any of the
functions.
The basic form is therefore Presenter:action
:
<a n:href="Home:default">home</a>
If we link to the action of the current presenter, we can omit its name:
<a n:href="default">home</a>
If the action is default
, we can omit it, but the colon must remain:
<a n:href="Home:">home</a>
Links may also point to other modules. Here, the links are
distinguished into relative to the submodules, or absolute. The principle is analogous to disk paths, only instead of slashes
there are colons. Let's assume that the actual presenter is part of module Front
, then we will write:
<a n:href="Shop:Product:show">link to Front:Shop:Product:show</a>
<a n:href=":Admin:Product:show">link to Admin:Product:show</a>
A special case is linking to itself. Here we'll write this
as the
target.
<a n:href="this">refresh</a>
We can link to a certain part of the HTML page via a so-called fragment after the #
hash symbol:
<a n:href="Home:#main">link to Home:default and fragment #main</a>
Absolute Paths
Links generated by link()
or n:href
are always absolute paths (i.e., they start with /
),
but not absolute URLs with a protocol and domain like https://domain
.
To generate an absolute URL, add two slashes to the beginning (e.g., n:href="//Home:"
). Or you can switch the
presenter to generate only absolute links by setting $this->absoluteUrls = true
.
Link to Current Page
The target this
will create a link to the current page:
<a n:href="this">refresh</a>
At the same time, all parameters specified in the signature of the render<View>()
or
action<Action>()
method are transferred. So if we are on the Product:show
and id:123
pages, the link to this
will also pass this parameter.
Of course, it is possible to specify the parameters directly:
<a n:href="this refresh: 1">refresh</a>
Function isLinkCurrent()
determines if the target of the link is the same as the current page. This can be used,
for example, in a template to differentiate links, etc.
The parameters are the same as for the link()
method, but it is also possible to use the wildcard *
instead of a specific action, which means any action of the presenter.
{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>
An abbreviated form can be used in combination with n:href
in single element:
<a n:class="isLinkCurrent() ? active" n:href="Product:detail">...</a>
Wildcard character *
replaces presenter's action only, not presenter itself.
To find out if we are in a certain module or its submodule we can use isModuleCurrent(moduleName)
function.
<li n:class="isModuleCurrent('MyEshop:Users') ? active">
<a n:href="Product:">...</a>
</li>
Links to Signal
The target of the link may not only be the presenter and action, but also the signal (they call the method
handle<Signal>()
). The syntax is as follows:
[//] [sub-component:]signal! [#fragment]
The signal is therefore distinguishes by exclamation mark:
<a n:href="click!">signal</a>
You can also create a link to the signal of the subcomponent (or sub-subcomponent):
<a n:href="componentName:click!">signal</a>
Links in Component
Because components are separate reusable units that should
have no relations to surrounding presenters, the links work a little differently. The Latte attribute n:href
and tag
{link}
and component methods such as link()
and others always consider the target as the signal
name. Therefore it is not necessary to use an exclamation mark:
<a n:href="click">signal, not an action</a>
If we want to link to presenters in the component template, we use the tag {plink}
:
<a href="{plink Home:default}">home</a>
or in the code
$this->getPresenter()->link('Home:default')
Aliases
Sometimes it's useful to assign an easily memorable alias to a Presenter:action pair. For example, you could name the homepage
Front:Home:default
simply as home
or Admin:Dashboard:default
as admin
.
Aliases are defined in the configuration under the key
application › aliases
:
application:
aliases:
home: Front:Home:default
admin: Admin:Dashboard:default
sign: Front:Sign:in
In links, they are written using the at symbol, for example:
<a n:href="@admin">administration</a>
They are supported in all methods that work with links, such as redirect()
and similar.
Invalid Links
It may happen that we create an invalid link – either because it refers to a non-existing presenter, or because it passes
more parameters that the target method receives in its signature, or when there can't be a generated URL for the targeted action.
What to do with invalid links is determined by the static variable Presenter::$invalidLinkMode
. It can have one of
these values (constants):
Presenter::INVALID_LINK_SILENT
– silent mode, returns symbol#
as URLPresenter::INVALID_LINK_WARNING
– E_USER_WARNING will be producedPresenter::INVALID_LINK_TEXTUAL
– visual warning, the error text is displayed in the linkPresenter::INVALID_LINK_EXCEPTION
– InvalidLinkException will be thrown
The default setup in production mode is INVALID_LINK_WARNING
and in development mode is
INVALID_LINK_WARNING | INVALID_LINK_TEXTUAL
. INVALID_LINK_WARNING
doesn't kill the script in the
production environment, but the warning will be logged. In the development environment, Tracy will intercept the warning and display the error bluescreen. If the
INVALID_LINK_TEXTUAL
is set, presenter and components return error message as URL which stars with
#error:
. To make such links visible, we can add a CSS rule to our stylesheet:
a[href^="#error:"] {
background: red;
color: white;
}
If we don't want warnings to be produced in the development environment we can turn on silent invalid link mode in the configuration.
application:
silentLinks: true
LinkGenerator
How to create links with the method link()
comfort, but without the presence of a presenter? That's why here is
Nette\Application\LinkGenerator.
LinkGenerator is a service that you can have passed through the constructor and then create links using its method
link()
.
There is a difference compared to presenters. LinkGenerator creates all links as absolute URLs. Furthermore, there is no
“current presenter”, so it is not possible to specify only the name of the action link('default')
or the relative
paths to the modules.
Invalid links always throw Nette\Application\UI\InvalidLinkException
.