3. Twig's three tags
Twig parses just three simple tags:
{# comment tag - aren't rendered and they are also
multi-line
#} – do nothing!
{{ 'print tag' }}
– say something!
{% set this = 'block tag' %}
- do something!
4.
5.
6. The Lexer
The lexer tokenizes a template source code into a token stream. The default
lexer recognizes 13 different token types.
Here is the output for the Hello {{ name }} template:
TEXT_TYPE(Hello )
VAR_START_TYPE()
NAME_TYPE(name)
VAR_END_TYPE()
EOF_TYPE()
7. The Parser
The parser converts the token stream into an AST (Abstract Syntax Tree), or
a node tree. The core extension defines the basic nodes like: for, if, ... and the
expression nodes.
Here is the output for the Hello {{ name }} template:
Twig_Node_Module(
Twig_Node_Text(Hello )
Twig_Node_Print(
Twig_Node_Expression_Name(name)
)
)
9. The Compiler
The last step is done by the compiler. It takes a node tree as an input and
generates PHP code usable for runtime execution of the template.
The generated template for a Hello {{ name }} template reads as follows:
/* Hello {{ name }} */
class __TwigTemplate_1121b6f109fe93ebe8c6e22e3712bceb extends Twig_Template
{
protected function doDisplay(array $context, array $blocks = array())
{
// line 1
echo "Hello ";
echo twig_escape_filter($this->env, $this->getContext($context, "name"), "html", null,
true);
}
// some more code
}
13. FOR Loops
{% for user in users %}
{{user.name}}
{% else %}
{{ ‘No users’ }}
{% endfor %}
{% for i in 0..10 %}
{% for l in 'a'..'z' %}
{% for l in 'a'|upper..'z'|upper %}
{% for i in 0|range(10, 2) %}
{% for blog in blogs %}
<div class="link {{ cycle(['even', 'odd'], loop.index0) }}">
{{ blog.description }}
</div>
{% endfor %}
14. IF Tag
Multiple branches:
{% if kenny.sick %}
Kenny is sick.
{% elseif kenny.dead %}
You killed Kenny! You bastard!!!
{% else %}
Kenny looks okay --- so far
{% endif %}
Ternary operator:
{{ human.alive ? ‘It’s alive’ : ‘Wasted’ }}
15. - define a macro in a separate twig file:
- include your reusable macro where you want:
MACROS - a reusable and configurable
snippet of HTML
17. Spaceless
Use the spaceless tag to remove whitespace between HTML tags, not
whitespace within HTML tags or whitespace in plain text:
{% spaceless %}
<div>
<strong>foo bar</strong>
</div>
{% endspaceless %}
{# output will be <div><strong>foo bar</strong></div> #}
{% set value = 'no spaces' %}
<li> {{- value }} </li>
{# outputs '<li>no spaces </li>' #}
18. Verbatim
The verbatim tag marks sections as being raw text that should not be parsed.
For example to put Twig syntax as example into a template you can use this
snippet:
{% verbatim %}
<ul>
{% for item in seq %}
<li>{{ item }}</li>
{% endfor %}
</ul>
{% endverbatim %}
You can also use this tag to avoid the conflict with the default angular.js syntax,
if you do not want to change it.
19. The i18n extension
To use it, first, install the Extensions library.
You need to register this extension before using the trans block, then configure
the gettext extension:
// Set language to French
putenv('LC_ALL=fr_FR');
setlocale(LC_ALL, 'fr_FR');
// Specify the location of the translation tables
bindtextdomain('myAppPhp', 'includes/locale');
bind_textdomain_codeset('myAppPhp', 'UTF-8');
// Choose domain
textdomain('myAppPhp');
{% trans "Hello World!" %}
{% trans string_variable %}
{% trans %}
Hello {{ name }}
{% endtrans %}
21. Setting your own custom syntax
You may want to use simultaneously the default syntax of
angular( {{ }} ) with twig - what to do?
Change the twig default syntax to your preferred one!
22. Creating a TWIG extension
Twig is very customizable, and allows you to create custom tools, like tags,
filters, operators, functions by extending the core(libtwigExtensionCore.php) .
The principle of creating an extension is the same for any element you
wish to customize: you create a class which extends the Twig_Extension
abstract class, then overwrite the desired function, and inject your service or
create a custom function which you intend to use in the templates.
23. use it in your templates:
{{ entityHelper.attributeByStore(promo, attribute) }}
24. Sandbox
• It’s a regular Twig extension, {% sandbox %}
• Disabled by default.
• It allows to restrict the functions, filters, tags and object properties used in the
templates.
• It’s based on security policies.
$loader = new Twig_Loader_Filesystem('...');
$twig = new Twig_Environment($loader, array());
$properties = array(‘User’ => array('name', 'address'));
$policy = new Twig_Sandbox_SecurityPolicy(
array(), array(), array(), $properties, array()
);
$sandbox = new Twig_Extension_Sandbox(
$policy, true // all templates are sandboxed
);
$twig->addExtension($sandbox);
25. The template now displays an error:
{% sandbox %}
{% include 'user.html' %}
{% endsandbox %}
{{ user.name }} - ok
{{ user.address }} - ok
{{ user.age }} - is not accessible
Whoops, looks like something went wrong.
User: {{ user.age }}
Calling "age" property on a "User" object is not allowed …
26. Security policy arguments:
$policy = new Twig_Sandbox_SecurityPolicy(
$tags,
$filters,
$methods,
$properties,
$functions
);
Allow just 3 filters:
$policy = new Twig_Sandbox_SecurityPolicy(
$tags,
array('escape', 'upper', 'lower'),
$methods,
$properties,
$functions
);
27. {{ include }} vs {% include %}
1) If you want to store contents of a file in a variable if you want to repeat it twice:
{% set content = include('test.twig') %}
Instead of:
{% set content %}
{% include 'test.twig' %}
{% endset %}
2) If you want to add filters:
{{ include('alert.twig') | upper }}
Its tag equivalent:
{% set temp %}
{% include 'alert.twig' %}
{% endset %}
{{ temp | upper }}
Also, according to the documentation, it looks recommended to use {{ include() }} to
fit with best practices.
28. Conditional layouts
{% extends request.ajax ? "base_ajax.html" : "base.html" %}
{% block content %}
This is the content to be displayed.
{% endblock %}
Dynamic inclusion of a template:
{% include var|default('index') ~ '_foo.html' %}
29. Accessing an object attribute
{{ user.name }}
name can be:
* an item on an array
* property on an object
* getName()
{{ user[‘name’] }}
or you can force it to *just* fetch “name” as an array
item