You are browsing the unmaintained documentation for old Nette 2.0. See documentation for current Nette.

Templating

Templates are a tremendous feature of Nette Framework which eases your work and ensures the output is protected against vulnerabilities, such as XSS.

  • you will learn how to use the macros
  • blocks and inheritance
  • using and creating the helpers
  • creating user-defined macros
  • avoiding security vulnerabilities

Although PHP is originally a templating language it isn't suited for writing templates. Let's have a look at an example of PHP template that prints an array $items as a list:

<?php if ($items): ?>
    <?php $counter = 1 ?>
    <ul>
    <?php foreach ($items as $item): ?>
        <li id="item-<?php echo $counter++ ?>"><?php
        echo htmlSpecialChars(mb_convert_case($item, MB_CASE_TITLE)) ?>
        </li>
    <?php endforeach ?>
    </ul>
<?php endif?>

The code is rather confusing and also we must not forget to call htmlSpecialChars function. That's why there are so many different template engines for PHP. One of the best template engines is part of Nette Framework and it is called Latte. You'll love it!

Latte

The same template is written easily in Latte:

<ul n:if="$items">
{foreach $items as $item}
    <li id="item-{$iterator->counter}">{$item|capitalize}</li>
{/foreach}
</ul>

As you can see there are two types of macros:

  • macro in braces, for example {foreach …}
  • n:macro, for example n:if="…"

Macros

You can find detailed description of all the default macros on the extra page. Furthermore, you can make your own user-defined macros.

Each pair macro, such as {if} … {/if}, operating upon single HTML element can be written in n:macro notation. So, it is possible to write the {foreach} macro in the same manner:

<ul n:if="$items">
    <li n:foreach="$items as $item">{$item|capitalize}</li>
</ul>

With n:macros you can do much more interesting tricks as you will see in a moment.

{$item|capitalize} macro which prints the $item variable contains so called helper, in this case the capitalize helper which makes the first letter of each word uppercase.

Very important feature of Latte is that it escapes variables by default. Escaping is needed when printing a variable because we have to convert all the characters which have a special meaning in HTML to other sequences. In case we forget it can lead to a serious security hole called Cross Site Scripting (XSS).

Because of different escaping functions that are needed in different documents and different parts of a page, Latte features a unique technology of Context-Aware Escaping which recognizes the context in which the macro is placed and chooses the right escaping mode. You don't have to worry that your coder forgets about it causing you goose bumps because of a security hole. Which is great!

If the $item variable stores an HTML code and you want to print it without any alteration you just add modifier noescape: {$item|noescape} (since release 2.0.11) or put the exclamation mark right after the opening brace: {!$item}. Forgetting the exclamation mark won't cause any security holes in spirit of „less code, more security“ principle.

You can still use PHP inside the macros normally, including comments as well. But Latte also extends the PHP syntax with three pleasant features:

  1. array can be written as [1, 2, 3], which is the same as array(1, 2, 3) in PHP
  2. we can omit quotes around the strings consisting of letters, numbers and dashes
  3. short condition notation $a ? 'b' which is the same as $a ? 'b' : null in PHP

For example:

{foreach [a, b, c] as $id} ... {/foreach}

{$cond ? hello}  // prints 'hello' if $cond equals true

Latte also has a {* comment macro *} which doesn't get printed to the output.

n:macros

We showed that n:macros are supposed to be written directly into HTML tags as their special attributes. We also said that every pair macro (e.g. {if} … {/if}) can be written in n:macro notation. The macro then corresponds to the HTML element in which it is written:

{var $items = ['I', '♥', 'Nette Framework']}

<p n:foreach="$items as $item">{$item}</p>

Prints:

<p>I</p>
<p></p>
<p>Nette Framework</p>

By using inner- prefix we can alter the behavior so that the macro applies only to the body of the element:

<div n:inner-foreach="$items as $item">
    <p>{$item}</p>
    <hr>
</div>

Prints:

<div>
    <p>I</p>
    <hr>
    <p></p>
    <hr>
    <p>Nette Framework</p>
    <hr>
</div>

Or by using tag- prefix the macro is applied on the HTML tags only:

<p><a href="{$url}" n:tag-if="$url">Title</a></p>

Depending on the value of $url variable this will print:

// when $url is empty
<p>Title</p>

// when $url equals 'https://nette.org'
<p><a href="https://nette.org">Title</a></p>

However, n:macros are not only a shortcut for pair macros, there are some pure n:macros as well, for example n:href or the coder's best friend n:class macro.

Helpers in Latte

Latte allows calling helpers by using the pipe sign notation (preceding space is allowed):

<h1>{$heading|upper}</h1>

Helpers (or modifiers) can be chained, in that case they apply in order from left to right:

<h1>{$heading|lower|capitalize}</h1>

Parameters are put after the helper name separated by colon or comma:

<h1>{$heading|truncate:20,''}</h1>

See the summary of standard helpers and how to make user-defined helpers.

Performance

Latte is fast. It compiles the templates to native PHP code and stores them in cache on the disk. So they are as fast as if they would have been written in pure PHP.

The template is automatically recompiled each time we change the source file. While developing you just need to edit the templates in Latte and changes are visible in your browser instantly.

Debugging

With each error or typo you will be informed by the Debugger with all the luxury. The template source code is displayed and the red line marks the error showing error message as well. With just a single click you can open the template in your favorite editor and fix the error at once. Easy peasy!

If you are using an IDE with code stepping you can go through the generated PHP code of the template.

Usability

Latte syntax wasn't invented by engineers but came up from webdesigner's practical requests. We were looking for the friendliest syntax with which you can write even the most problematic constructions comfortably enough. You will be surprised how much help Latte can be.

You can find macros for advanced layout managing, for template inheritance, nested blocks and so on. Syntax comes from PHP itself so you don't have to learn anything new and you can leverage your know-how.

Context-Aware Escaping

Although the Cross Site Scripting (XSS) is one of the trivial ways of exploiting a web page it is the most common vulnerability but very serious. It can lead to identity theft and so on. The best defense is consistent escaping of printed data, ie. converting the characters which have a special meaning in the given context.

If the coder omits the escaping a security hole is made. That's why template engines implement automated escaping. The problem is that the web page has different contexts and each has different rules for escaping printed data. A security hole then shows up if the wrong escaping functions are used.

But Latte is sophisticated. It features unique technology of Context-Aware Escaping which recognizes the context in which the macro is placed and chooses the right escaping mode. What does that mean?

Latte doesn't need any manual work. All is done automatically, consistently and correctly. You don't have to worry about security holes.

Lets see how it works:

<p onclick="alert({$movie})">{$movie}</p>

<script>var movie = {$movie};</script>

If $movie variable stores 'Amarcord & 8 1/2' string it generates the following output. Notice different escaping used in HTML and JavaScript and also in onclick attribute:

<p onclick="alert(&quot;Amarcord &amp; 8 1\/2&quot;)">Amarcord &amp; 8 1/2</p>

<script>var movie = "Amarcord & 8 1\/2";</script>

Thanks to Context-Aware Escaping the template is simple and your application perfectly secured against Cross Site Scripting. You can use PHP variables natively inside the JavaScript!

A pretty output

Sticklers will enjoy the look of the HTML output which Latte generates. All tags are indented as they are supposed to. The code looks like it has been processed with some kind of HTML code beautifier :-)

User-defined macros

Latte provides API for making your own macros. It isn't difficult at all. Macros are added in sets (a set can consist of a single macro).

$latte = new Nette\Latte\Engine;

// lets create a set
$set = new Nette\Latte\Macros\MacroSet($latte->compiler);

// add new pair macro {try} ... {/try}
$set->addMacro(
    'try', // macro name
    'try {',  // PHP code replacing the opening brace
    '} catch (\Exception $e) {}' // code replacing the closing brace
);

If we omit the last parameter of addMacro() method, we denote the macro is not paired.

PHP code in the second and third parameter can contain tags:

  • %node.word – inserts the first macro argument
  • %node.array – inserts the macro arguments formated as a PHP array
  • %node.args – inserts the macro arguments formated as PHP code
  • %escape(...) – replaced by the current escape function
  • %modify(...) – replaced by a sequence of modifiers

For example:

$set->addMacro('if', 'if (%node.args):', 'endif');

If the macro logic is more complex we can use callbacks or lambda functions instead of strings. In the first parameter they will get MacroNode object which represents the current macro, the second parameter is PhpWriter object which helps with generating the output code.

$set->addMacro('if', function($node, $writer) {
    return $writer->write('if (%node.args):');
}, 'endif');

Helpers

In templates we can use functions which change or format the data to a form we want. They are called helpers. See the summary of the default helpers.

Helper can be registered by any callback or lambda function:

$template->registerHelper('shortify', function ($s) {
    return mb_substr($s, 0, 10); // shortens the text to 10 characters
});

In this case it would be better for the helper to get an extra parameter:

$template->registerHelper('shortify', function ($s, $len = 10) {
    return mb_substr($s, 0, $len);
});

We call it in a template like this:

<p><?php echo $template->shortify($text, 100); ?></p>

Latte simplifies the notation – helpers are denoted by the pipe sign, they can be chained (they apply in order from left to right). Parameters are separated by colon or comma:

<p>{$text|shortify:100}</p>

Independent template usage

While using presenters we usually don't need to do anything but to write a template. Everything else does the framework for us. However, we can use the templates independently, for example in existing application which doesn't use Nette.

Template classes are in Nette\Templating namespace and the core class is Nette\Templating\Template. Here is an example of how to work with it:

use Nette\Templating\Template;

$template = new Template;
// passing parameters to the template:
$template->firstName = 'John';
$template->lastName = 'Doe';
$template->setSource('
    <em><?php echo htmlspecialchars($firstName) ?></em>
    <strong><?php echo htmlspecialchars($lastName) ?></strong>
');
$template->render();

render() method renders the template, ie. the PHP script we passed as a parameter to getSource() method. The parameters will be available in local variables $firstName and $lastName. Additionally, the template object is stored in the $template variable.

If the template is stored as a file it is better to use FileTemplate class:

use Nette\Templating\FileTemplate;

$template = new FileTemplate('template.latte'); // template file
// $template->setFile('template.latte'); // file path can be specified also later
$template->firstName = 'John';
$template->lastName = 'Doe';
$template->render(); // renders the template

We need to register the helpers if we want to use them in the template. Default helpers are registered like this:

$template->registerHelperLoader('Nette\Templating\Helpers::loader');

A template can be preprocessed with one or more filters. Filter is a function which gets the content of the template as a parameter and returns altered template. Any callback or lambda function can be registered as a filter.

// filter which replaces 'apple' with 'pizza'
$template->registerFilter(function ($s) {
    return str_replace('apple', 'pizza', $s);
});

For registering the filter in presenters and components it is best to override templatePrepareFilters method.

The most complex filter is Latte:

$template->registerFilter(new Nette\Latte\Engine);

We get native PHP template after applying all the registered filters. It is saved in the cache so the filters are applied just once. The cache is invalidated automatically once the source code is changed and it is saved in special format which allows the files to be loaded with include. That's why you have to specify a storage where the cache files will be saved:

$template->setCacheStorage(new Nette\Caching\Storages\PhpFileStorage('temp'));

You can register the Latte filter in the onPrepareFilters event handler to avoid creating and registering the filter every time the filtered templates are saved in the cache:

$template->onPrepareFilters[] = function($template) {
    $template->registerFilter(new Nette\Latte\Engine);
};

Now you know everything about templates.