Macro loader

This short tutorial will show you, how to create and register custom macros.

Create macro

First, we create macroSet and add all our macros. How to register macros to template will be shown later.

Note: in Nette 2.1 and older, you have to use Nette\Latte namespace instead of Latte.

$set = Latte\Macros\MacroSet::install($latte->getCompiler());
$nMacro <<<'EOT'
if ($_l->tmp = array_filter(%node.array)) {
        echo ' id="' . %escape(implode("_", $_l->tmp)) . '"';
}
EOT;
$set->addMacro('id', null, null, $nMacro);

$_l is a simple local storage object, which you can use to store temporary variables.

Use case in template:

<div n:id="show, true ? success : error">Id success</div>
<div n:id="show, false ? success : error">Id error</div>

Result:

<div id="show_success">Id success</div>
<div id="show_error">Id error</div>

Syntax

Macro has few basic parameters

addMacro($name, $begin, $end = null, $attr = null);

Parameters $begin and $end are used to create classic macro, parameter $attr is used for n:macro.

For deeper knowledge about those parameters you can check Classic vs n:macro section.

This should seem more clear now:

$set->addMacro('id', null, null,
  'if ($_l->tmp = array_filter(%node.array))
     echo \' id="\' . %escape(implode("_", $_l->tmp)) . \'"\'
');

We can use special aliases like %node.word, %node.array, %node.args, %escape(), %modify(), %var and %raw while writing content code of macro. For more see documentation. For example, when we write in macro %escape($_template->var), it will have same result as {$var} in template.

For better understanding, you can check some examples in Nette: CoreMacros and FormMacros

$attr as callback

In case of long method you can register callback to standalone method.

$set->addMacro('id', null, null, [$this, 'macroId']);

// ...


/**
 * n:id="..."
 */
public function macroId(MacroNode $node, PhpWriter $writer)
{
    return $writer->write('if ($_l->tmp = array_filter(%node.array)) echo \' id="\' . %escape(implode("_", $_l->tmp)) . \'"\'');
}

Registration

As mentioned in the first part, after creating macroSet, we have have to register it. Only after registration macros can be used in template.

First we create separate class and place it o libs folder.

CustomMacros.php

use Latte\MacroNode;
use Latte\PhpWriter;

class CustomMacros extends Latte\Macros\MacroSet
{

    public static function install(Latte\Compiler $compiler)
    {
        $set = new static($compiler);
        $set->addMacro('id', null, null, [$set, 'macroId']);
    }


    /**
     * n:id="..."
     */
    public function macroId(MacroNode $node, PhpWriter $writer)
    {
        return $writer->write('if ($_l->tmp = array_filter(%node.array)) echo \' id="\' . %escape(implode("_", $_l->tmp)) . \'"\'');
    }

}

Then we add our class to latte compilation in config.neon

factories:
    nette.latte:
        class: Latte\Engine
        setup:
            - CustomMacros::install(::$service->getCompiler())

Since Nette 2.1-dev there exists special section for macros:

nette:
    latte:
        macros:
            - CustomMacros::install

Classic macro vs. n:macro

addMacro($name, $begin, $end = null, $attr = null);

Using only $begin and $end parameters we create classic macro.

Using only $attr parameter we create n:macro.

To combine both in universal macro, we have to register anonymous function or define all parameters.

Use case

Presenter

# obě makra (všechny parametry)
$set->addMacro("test1", "start", "end", "attributes");

# obě makra (anonymní funkce, callbacks)
$set->addMacro("test1", function($node, $writer) { ... });
$set->addMacro("test1", [$this, 'myMacro'];
$set->addMacro("test1", ['Macros', 'myMacro']);

# pouze n:makro
$set->addMacro("test2", null, null, "attributes");

# pouze klasické makro
$set->addMacro("test3", "start", "end");

Template

{test1 "parameter1"}Lorem lipsum..{/test1}

<div n:test1="parameter1">Lorem lipsum..</div>

<span n:test2="parameter1">Lorem lipsum..</span>

{test3 "parameter1"}Lorem lipsum..{/test3}

Html

<?php start ?>Lorem lipsum..<?php end ?>

<div <?php atributy ?>>Lorem lipsum..</div>

<span <?php atributy?>>Lorem lipsum..</span>

<?php start ?>Lorem lipsum..<?php end ?>