Link Generation

The creation of links belongs to the strongest features of the Nette Framework. Thanks to two-way routing you don't have to hardcode your URLs or nastily assemble them. You can just refer to the actions of presenters, and pass them parameters and the framework will generate URLs by itself. Creating links is as easy as calling a function. You will really like it!

When programming and coding templates, we don't have to care about URLs design, we will refer directly to the action of the presenter, that's, for example, the already mentioned Product:show.

Most often we create links in templates. To make it as easy as possible the framework offers three tags. The smartest of them is n:href

<a n:href="Product:show $productId">product 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 directly an action of a presenter. The syntax is

[Presenter:]action [,] [arg1] [, arg2] [, ...]

After clicking on the link, method ProductPresenter::renderShow() will get its word and as parameter $id will get the value of $productId. We can pass even more parameters in the same way, just like we call a method. Could it get any easier?

Best practice is to write the presenter with a capital letter and the action without. The separator is a colon.

Besides that, it's even possible to pass named parameters. The next link passes the parameter lang with value cs:

<a n:href="Product:show $productId, lang => cs">product detail</a>

Although the method renderShow doesn't have $lang in its declaration, it can read the value of this parameter by calling $lang = $this->getParameter('lang').

If we have all parameters in an array, we can expand them with (expand) operator:

{var $args = [$productId, lang => cs]}
<a n:href="Product:show (expand) $args">product detail</a>

If the template, in which we are creating links, is part of the Product presenter, we can omit the name of the presenter and write directly n:href="show $productId". Similarly, if a link leads to the an action named default, you can skip that and write n:href="Product: $id" (don't forget the colon).

Links can even refer to other modules. Here we distinguish, if it's referring “relatively” to a submodule, or “absolutely” to a different module – then the path begins with a colon. Let's assume that the actual presenter is part of module Front, then we will write:

<a n:href="Shop:Product:show">link for Front:Shop:Product:show</a>
<a n:href=":Admin:Product:show">link for Admin:Product:show</a>

A special case is linking to itself. Here we'll write this as the target.

The generated link is in absolute path format. When you want to generate an absolute link including the domain, for example, http://example.com, simply supply two slashes at the beginning n:href="//show $productId". If we set the property $absoluteUrls in presenter to true, all the links will be absolute by default.

We can refer to specific parts on the page using so-called fragments, or anchors, with the hash # symbol:

<a n:href="show#comments">link to Product:show and fragment #comments</a>

The attribute n:href is really handy if we are creating an HTML tag <a>. When we want to have this link elsewhere, for example in the text of the template, we can use the {link} tag with the same internal syntax:

The address is: {link Product:show $productId}

Read more details about the syntax of Latte templates.

The presenter can easily determine if the link target is the same as the current page. This can be used, for example, in a layout template to add a CSS class to a link to the current page or change the page content.

This is done using the method $presenter->isLinkCurrent(destination [, arg [, arg ...]]).

Instead of a specific action it is possible to use a wildcard character *, which means any action of the presenter.

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

	<!-- inside element A it is not necessary to repeat link destination: -->
	<li><a n:class="$presenter->isLinkCurrent() ? active" n:href="Product:detail">...</a></li>

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

{if !$presenter->isLinkCurrent('Admin:login')}
	<a href="{link Admin:login}">Sign in!</a>
{/if}

Wildcard character * replaces presenter's action only, not presenter itself. Link to current module (or it's submodule) can be determined by $presenter->isModuleCurrent(moduleName) method.

<ul class="menu">
	<li n:class="$presenter->isModuleCurrent('MyEshop:Users') ? active">
		Users
		<ul class="submenu">
			<li><a n:href="MyEshop:Users:Search:default">Search users</a></li>
			<li><a n:href="MyEshop:Users:Add:default">Add new user</a></li>
		</ul>
	</li>
</ul>

Linking in Presenter

Presenter and a component have the method link, which can be used to create links just like in a template. The first argument is presenters target action, followed by passed arguments:

$url = $this->link(destination [,arg [,arg ...]]);

They can also be passed using an array. Examples:

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

$url = $this->link('Product:show', [$productId, 'lang' => 'en']);

If you pass false as method parameter when generating a link, it won't be added to the link at all. The solution is to define this parameter with default value true or false. Nette will then understand that its type is boolean, and it will be passed to the URL as 1 or 0, and converted back to a boolean when processed by a presenter.

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 definition, 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 URL
  • Presenter::INVALID_LINK_WARNING – E_USER_WARNING will be produced
  • Presenter::INVALID_LINK_TEXTUAL – visual warning, the error text is displayed in the link
  • Presenter::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