SlideShare ist ein Scribd-Unternehmen logo
1 von 204
Downloaden Sie, um offline zu lesen
Javier EguiluzSeptember 22, 2015
Twig
TRACK ROOM DATE SPEAKER
Symfony 115
Mastering
License of this presentation
creativecommons.org/licenses/by-nc-sa/3.0
ABOUT ME
Javier Eguiluz
Symfony Evangelist
ABOUT THIS
TALK
We won't talk about
Twig basics.
We won't provide all
the low-level details.
How can
I create a
theme? Which is
the syntax of
Twig?
Read the excellent Twig
documentation to get
those details.
DRUPAL
& TWIG
Fast Easy to learn
Documented Concise Full featured
Extensible Tested Useful errors
Secure
Main Twig features
My favorite feature
Consistent
My favorite feature
Twig defines a very
small set of features…
… which are enough to
create any template
Consistent
same syntax and
behavior since day one!
easy to learn!
«Using Twig templates
is the best decision
Drupal ever made»
DRUPAL 8
TWIG
Built-in Drupal templates
use ~30% of the
available Twig features.
AGENDA
Defensive
programming
White spaces
Debug Escaping
Reusing
templates
Dates
Dynamic
templates
Cool
features
Variables
Agenda
ACCESSING
VARIABLES
WHY IS THIS IMPORTANT??
Because you can easily
improve the performance of
your site/app.
Accessing simple variables
!
<p class="comment__author">{{ author }}</p>
<p class="comment__time">{{ created }}</p>
<p class="comment__permalink">{{ permalink }}</p>
core/themes/bartik/templates/comment.html.twig
Accessing complex variables
!
<nav>{{ content.links }}</nav>
core/themes/bartik/templates/comment.html.twig
Accessing complex variables
!
<nav>{{ content.links }}</nav>
core/themes/bartik/templates/comment.html.twig
This is how Twig resolves complex variables
<nav>{{ content.links }}</nav>
!
$content['links']
$content->links
$content->links()
$content->getLinks()
$content->isLinks()
null
Twig tries all these alternatives
and uses the first one that exists.
And what about
performance?
Resolving variables is quite expensive
<nav>{{ content.links }}</nav>
!
$content['links']
$content->links
$content->links()
$content->getLinks()
$content->isLinks()
null
Resolving a variable is the most
expensive Twig task, specially
for very complex templates.
Improving Twig performance
• Twig provides a PHP extension.
• This extension only implements
the variable resolving logic.
• See twig.sensiolabs.org/doc/
installation.html#installing-the-
c-extension
EXPECTED

PERFORMANCE
INCREASE
15%
Some Drupal variables names are special
!
$variables['site_slogan']['#markup'] = ...
!
{{ site_slogan.#markup }}
core/themes/bartik/bartik.theme
This doesn't work because
of the # character
Some Drupal variables names are special
!
$variables['site_slogan']['#markup'] = ...
!
{{ site_slogan.#markup }}
core/themes/bartik/bartik.theme
This doesn't work because
of the # character
{{ site_slogan['#markup'] }}
{{ attribute(site_slogan, '#markup') }}
DEFENSIVE
PROGRAMMING
WHY IS THIS IMPORTANT??
Because sooner or later
errors will happen. What
matters is how you deal
with them.
Dealing with undefined/empty variables
is empty defaultis defined
is null {% if %}
The two recommended safeguards
{% if variable %}
...
{% endif %}
!
!
Hi {{ variable|default('user') }}
The two recommended safeguards
{% if variable %}
...
{% endif %}
!
!
Hi {{ variable|default('user') }}
It checks that variable is not null
or empty or zero
!
ONLY works if variable is defined
The two recommended safeguards
{% if variable %}
...
{% endif %}
!
!
Hi {{ variable|default('user') }}
It checks that variable is not null
or empty or zero
!
ONLY works if variable is defined
It checks that variable is not null,
empty or undefined
!
It ALWAYS works as expected
Combining both safeguards
{% if variable|default('user') %}
...
{% endif %} It doesn't matter if the variable is not
defined, because the expression will
always have a default value.
Checking that the variable is defined
{% if variable is defined %}
...
{% endif %} A good practice when the rendered
template cannot be sure about the
variables passed from the code.
!
In Drupal 8 this problem should not
happen (the variable list is strict).
Other safeguards available
{% if variable is null %} ... {% endif %}
!
!
{% if variable is empty %} ... {% endif %}
{% if variable is not empty %} ... {% endif %}
Be ready when iterating empty collections
{% for item in collection %}
...
{% else %}
There are no items.
{% endfor %}
Filter values before using them in the loop
{% for item in collection if item.published %}
...
{% else %}
There are no items.
{% endfor %}
Avoid missing templates
{{ include('menu.twig') }}
This will always work because our
theme will provide this template.
Avoid missing templates
{{ include('menu.twig') }}
This will always work because our
theme will provide this template.
Templates with dynamic
paths are very prone to error
{{ include('users/' ~ user.name ~ '/bio.twig') }}
Define fallback templates
{{ include([
'users/' ~ user.name ~ '/bio.twig',
'users/' ~ user.name ~ '/default.twig',
'common/user_bio.twig'
]) }}
Twig includes the first
template that exists
Avoid missing templates
• Sometimes it's not possible to provide fallback
templates.
• Moreover, in some cases, it's better to ignore the
missing template instead of displaying an error to
the user.
Ignore missing templates
{{ include('template.twig', ignore_missing = true) }}
!
{{ source('template.twig', ignore_missing = true) }}
!
{% embed 'template.twig' ignore missing %}
...
{% endembed %}
Ignore missing templates
{{ include('template.twig', ignore_missing = true) }}
!
{{ source('template.twig', ignore_missing = true) }}
!
{% embed 'template.twig' ignore missing %}
...
{% endembed %} NOTE
no underscore here
Twig filters defined by Drupal 8
{{ value|t }}
{{ value|trans }}
{{ value|passthrough }}
{{ value|placeholder }}
{{ value|drupal_escape }}
{{ value|safe_join }}
{{ value|without }}
{{ value|clean_class }}
{{ value|clean_id }}
{{ value|render }}
It's common for a long-
standing and complex project
to add and remove filters.
!
If Drupal removes a filter
used by your templates, your
site/app will break.
Declare filters as deprecated
new Twig_SimpleFilter('old_filter', ..., array(
'deprecated' => true,
'alternative' => 'new_filter'
));
Declare filters as deprecated
new Twig_SimpleFilter('old_filter', ..., array(
'deprecated' => true,
'alternative' => 'new_filter'
));
These deprecations notices are not displayed or logged
anywhere on Drupal yet.
NOTE
Avoid missing blocks
{% if 'title' is block %}
<title>{{ block('title') }}<title>
{% endif %}
This feature is not available yet. It will be included in the
upcoming 1.23 version of Twig.
NOTE
Avoid missing blocks
{% if 'title' is block %}
<title>{{ block('title') }}<title>
{% endif %}
WHITE
SPACES
WHY IS THIS IMPORTANT??
Because it will make your
templates more readable
and it will save you time.
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
The "problem" of white spaces
Twig template HTML page
<ul>
{% for i in 1..3 %}
<li>{{ i }}</li>
{% endfor %}
</ul>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
The "problem" of white spaces
Twig template HTML page
<ul>
{% for i in 1..3 %}
<li>{{ i }}</li>
{% endfor %}
</ul>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
The "problem" of white spaces
Twig template HTML page
<ul>
{% for i in 1..3 %}
<li>{{ i }}</li>
{% endfor %}
</ul>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
The "problem" of white spaces
Twig template HTML page
<ul>
{% for i in 1..3 %}
<li>{{ i }}</li>
{% endfor %}
</ul>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
The "problem" of white spaces
Twig template HTML page
<ul>
{% for i in 1..3 %}
<li>{{ i }}</li>
{% endfor %}
</ul>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
The "problem" of white spaces
Twig template HTML page
Removing white spaces
<ul>
{%- for i in 1..3 -%}
<li>{{ i }}</li>
{%- endfor -%}
</ul>
<ul>
{% spaceless %}
{% for i in 1..3 %}
<li>{{ i }}</li>
{% endfor %}
{% endspaceless %}
</ul>
Please, don't waste
your time dealing with
white spaces.
!
Twig templates
should be readable
HTML pages
should not
!
!
Twig templates
should be readable
HTML pages
should not
this is where you
work everyday
!
browsers get a minimized
and compressed HTML mess
Sometimes you
should add white
spaces…
White spaces around HTML attributes
<h2{{ title_attributes }}>{{ label }}</h2>
core/modules/block/templates/block.html.twig
White spaces around HTML attributes
<h2{{ title_attributes }}>{{ label }}</h2>
core/modules/block/templates/block.html.twig
White spaces around HTML attributes
<h2{{ title_attributes }}>{{ label }}</h2>
core/modules/block/templates/block.html.twig
no white space when
the attributes are empty
<h2 class="..."> ... </h2>
<h2> ... </h2>
Add white spaces to separate Twig & HTML
<h2 {{ title_attributes }}>{{ label }}</h2>
!
!
<h2 class="..."> ... </h2>
<h2 > ... </h2>
Add white spaces to separate Twig & HTML
<h2 {{ title_attributes }}>{{ label }}</h2>
!
!
<h2 class="..."> ... </h2>
<h2 > ... </h2>
white space when the
attributes are empty
Add white spaces to separate Twig & HTML
<h2 {{ title_attributes }}>{{ label }}</h2>
!
!
<h2 class="..."> ... </h2>
<h2 > ... </h2>
white space when the
attributes are empty
IT DOES NOT MATTER
Twig template is
more readable
HTML code with white
spaces is still valid
Hiding HTML code inside Twig strings
<div id="site-name"{{ hide_name ? ' class="hidden"' }}>
!
!
!
!
!
<div id="site-name">
<div id="site-name" class="hidden">
core/themes/bartik/templates/maintenance-page.html.twig
Hiding HTML code inside Twig strings
<div id="site-name"{{ hide_name ? ' class="hidden"' }}>
!
!
!
!
!
<div id="site-name">
<div id="site-name" class="hidden">
core/themes/bartik/templates/maintenance-page.html.twig
Hiding HTML code inside Twig strings
<div id="site-name"{{ hide_name ? ' class="hidden"' }}>
!
!
!
!
!
<div id="site-name">
<div id="site-name" class="hidden">
WARNING
HTML attributes
defined in Twig strings
are easy to overlook
core/themes/bartik/templates/maintenance-page.html.twig
Hiding HTML code inside Twig strings
<div id="site-name"{{ hide_name ? ' class="hidden"' }}>
!
!
!
!
!
<div id="site-name">
<div id="site-name" class="hidden">
WARNING
HTML attributes
defined in Twig strings
are easy to overlook
core/themes/bartik/templates/maintenance-page.html.twig
DANGER
If you miss this single
white space, the page
design breaks
Don't hide HTML code inside Twig strings
<div id="site-name" class="{{ hide_name ? 'hidden' }}">
!
!
!
!
!
<div id="site-name" class="">
<div id="site-name" class="hidden">
HTML & Twig
are decoupled
A single white space
won't break the page
Don't hide HTML code inside Twig strings
<div id="site-name" class="{{ hide_name ? 'hidden' }}">
!
!
!
!
!
<div id="site-name" class="">
<div id="site-name" class="hidden">
Valid HTML code
(tested with the W3C validator)
HTML & Twig
are decoupled
A single white space
won't break the page
DEBUG
WHY IS THIS IMPORTANT??
Because it will save you a
lot of time while developing
your templates.
Configure Twig behavior
# sites/default/services.yml
parameters:
twig.config:
debug: true
auto_reload: null
cache: true
Configure Twig behavior
# sites/default/services.yml
parameters:
twig.config:
debug: true
auto_reload: null
cache: true
Include debug information in
the rendered HTML contents
In production server,
always set it to false
HTML content of a rendered Drupal template
<div id="block-bartik-login" class="contextual-region block block-user block-user-login-block"
role="form">
<h2>User login</h2>
<div data-contextual-id="block:block=bartik_login:langcode=en"></div>
<div class="content">
!
<form class="user-login-form" data-drupal-selector="user-login-form" action="/node?destination=/
node" method="post" id="user-login-form" accept-charset="UTF-8">
!
<!-- ... -->
HTML content when Twig debug is enabled
<!-- THEME DEBUG -->
<!-- THEME HOOK: 'block' -->
<!-- FILE NAME SUGGESTIONS:
* block--bartik-login.html.twig
* block--user-login-block.html.twig
* block--user.html.twig
x block.html.twig
-->
<!-- BEGIN OUTPUT from 'core/themes/bartik/templates/block.html.twig' -->
<div id="block-bartik-login" class="contextual-region block block-user block-user-login-block"
role="form">
<h2>User login</h2>
<div data-contextual-id="block:block=bartik_login:langcode=en"></div>
<div class="content">
!
<!-- THEME DEBUG -->
<!-- THEME HOOK: 'form' -->
<!-- BEGIN OUTPUT from 'core/themes/classy/templates/form/form.html.twig' -->
<form class="user-login-form" data-drupal-selector="user-login-form" action="/node?destination=/
How to override the current template
<!-- THEME DEBUG -->
<!-- THEME HOOK: 'block' -->
<!-- FILE NAME SUGGESTIONS:
* block--bartik-login.html.twig
* block--user-login-block.html.twig
* block--user.html.twig
x block.html.twig
-->
<!-- BEGIN OUTPUT from 'core/themes/bartik/templates/block.html.twig' -->
How to override the current template
<!-- THEME DEBUG -->
<!-- THEME HOOK: 'block' -->
<!-- FILE NAME SUGGESTIONS:
* block--bartik-login.html.twig
* block--user-login-block.html.twig
* block--user.html.twig
x block.html.twig
-->
<!-- BEGIN OUTPUT from 'core/themes/bartik/templates/block.html.twig' -->
Drupal tried to use all these
templates…
How to override the current template
<!-- THEME DEBUG -->
<!-- THEME HOOK: 'block' -->
<!-- FILE NAME SUGGESTIONS:
* block--bartik-login.html.twig
* block--user-login-block.html.twig
* block--user.html.twig
x block.html.twig
-->
<!-- BEGIN OUTPUT from 'core/themes/bartik/templates/block.html.twig' -->
…before deciding to use this
template.
Drupal tried to use all these
templates…
Which variables are passed to the template?
Built-in templates include
comments with the full
list of variables passed to
the Twig template.
Easier way to introspect all variables
<pre>
{{ dump() }}
</pre>
Easier way to introspect all variables
<pre>
{{ dump() }}
</pre>
It dumps the contents
of all the variables
defined in the template.
It's better to dump just the variables you need
<pre>
{{ dump(label, title_attributes) }}
</pre>
It's better to dump just the variables you need
<pre>
{{ dump(label, title_attributes) }}
</pre>
It dumps only the
given variables
CAUTION!
Don't forget to rebuild your
cache after changing the
config files and templates.
drupalconsole.com
drupalconsole.com
$ drupal cache:rebuild
$ drupal c:r
ESCAPING
WHY IS THIS IMPORTANT??
Because it can prevent you
a lot of security-related
problems.
CAUTION!
Drupal has replaced the
default Twig escaping filter
by their own.
By default, contents are escaped for HTML
Hi {{ content }}!
$content = '<strong>John</strong>';
By default, contents are escaped for HTML
Hi {{ content }}!
$content = '<strong>John</strong>';
What you expect…
Hi John!
What you get…
Hi <strong>John
</strong>!
The "raw" filter prevents the escaping
Hi {{ content|raw }}!
$content = '<strong>John</strong>';
The "raw" filter prevents the escaping
Hi {{ content|raw }}!
$content = '<strong>John</strong>';
What you expect…
Hi John!
What you get…
Hi John!
What if contents are used in URLs or JS?
<a href="...?param={{ value }}"></a>
!
!
!
<script>
var variable = "{{ content }}";
</script>
What if contents are used in URLs or JS?
<a href="...?param={{ value }}"></a>
!
!
!
<script>
var variable = "{{ content }}";
</script>
WRONG HTML
ESCAPING
Applying different escaping strategies
<a href="...?param={{ value|e('url') }}"></a>
!
!
!
<script>
var variable = "{{ content|e('js') }}";
</script>
Escaping strategies available in Twig
{{ content|e('html') }}
{{ content|e('js') }}
{{ content|e('css') }}
{{ content|e('url') }}
{{ content|e('html_attr') }}
REUSING
TEMPLATES
WHY IS THIS IMPORTANT??
Because it allows you to
avoid repeating code and it
makes your themes easier
to maintain.
Lots of different ways to reuse templates
{% embed %} {% extends %}include()
{% set %} {% use %}macro()
How often are these alternatives used
{% embed %}
{% extends %} include( )
{% set %} {% use %}
macro( )
Always
Sometimes
Rarely
Lots of different ways to reuse templates
{% embed %} {% extends %}include()
{% set %} {% use %}macro()
Use {% extends %} to share layouts
Use {% extends %} to share layouts
1 layout with the common design elements
Use {% extends %} to share layouts
1 layout with the common design elements
+
4 simple pages which only define their contents
layout.twig
<!DOCTYPE html>
<html>
<head>
<title>
{% block title %}ACME website{% endblock %}
</title>
</head>
<body>
<div class="container">
{% block content %}{% endblock %}
</div>
</body>
</html>
layout.twig
<!DOCTYPE html>
<html>
<head>
<title>
{% block title %}ACME website{% endblock %}
</title>
</head>
<body>
<div class="container">
{% block content %}{% endblock %}
</div>
</body>
</html>
Other templates can reuse this layout
{% extends 'layout.twig' %}
!
{% block title %}Community{% endblock %}
{% block content %}
<div> ... </div>
{% endblock %}
When should you use {% extends %}
• To create the layout of your theme.
• If your site/app is very complex, create two
inheritance levels (base layout and section layouts).
layout.twig schedule.twig training.twig
extends layout.twig extends schedule.twig
Lots of different ways to reuse templates
{% embed %} {% extends %}include()
{% set %} {% use %}macro()
Reusing templates with include( )
!
{{ include('listing.twig') }}
!
!
<div>
{% for item in items %}
<h2>{{ item.title }}</h2>
<p>{{ item.content }}</p>
{% endfor %}
</div>
blog/index.twig
blog/listing.twig
When should you use include( )
• To reuse large fragments of code, such as sidebars,
navigation menus, etc.
Lots of different ways to reuse templates
{% embed %} {% extends %}include()
{% set %} {% use %}macro()
Repetitive HTML fragments
<div class="form-group">
<label for="{{ id }}">{{ label }}</label>
<input type="{{ type }}" class="form-control"
id="{{ id }}">
</div> Repeating the same HTML
code for all the form fields
is cumbersome
Reusing fragments with macro( )
{% macro form_field(id, label, type="text") %}
<div class="form-group">
<label for="{{ id }}">{{ label }}</label>
<input type="{{ type }}" class="form-control"
id="{{ id }}">
</div>
{% endmacro %}
Using "macros" inside templates
{% import _self as macro %}
!
<form>
{{ macro.form_field('first_name', 'First Name') }}
{{ macro.form_field('last_name', 'Last Name') }}
{{ macro.form_field('email', 'Email', 'email') }}
...
</form>
Using "macros" inside templates
{% import _self as macro %}
!
<form>
{{ macro.form_field('first_name', 'First Name') }}
{{ macro.form_field('last_name', 'Last Name') }}
{{ macro.form_field('email', 'Email', 'email') }}
...
</form>
Before using a macro, you must
"import" them (they can be
defined in a different template)
When should you use macro( )
• To reuse short fragments of code, usually in the
same template (e.g. listings, grids, forms, etc.)
• If your site/app is very complex, store all the macros
in a single file and reuse it from any other template.
Lots of different ways to reuse templates
{% embed %} {% extends %}include()
{% set %} {% use %}macro()
Grid-based design
embed allows to reuse inner page
structures (e.g. the 3-column grid)
Grid-based design
embed allows to reuse inner page
structures (e.g. the 3-column grid)
You can't use "include" to solve this problem
{{ include('common/grid_3.twig') }}
You can't use "include" to solve this problem
{{ include('common/grid_3.twig') }}
you can't change the included
contents (you include both the
structure and the content)
You can't use "extends" to solve this problem
{% extends 'common/grid_3.twig' %}
!
{% block column1 %} ... {% endblock %}
{% block column2 %} ... {% endblock %}
{% block column3 %} ... {% endblock %}
You can't use "extends" to solve this problem
{% extends 'common/grid_3.twig' %}
!
{% block column1 %} ... {% endblock %}
{% block column2 %} ... {% endblock %}
{% block column3 %} ... {% endblock %}
you can't make the whole structure
of the page (grid 2, grid 3, etc.)
because you can't extend from
multiple templates at the same time
Define a three-column grid template
<div class="row">
<div class="col-md-4">
{% block column1 %}{% endblock %}
</div>
!
<div class="col-md-4">
{% block column2 %}{% endblock %}
</div>
!
<div class="col-md-4">
{% block column3 %}{% endblock %}
</div>
</div>
Reuse the three-column grid template
{% embed 'common/grid_3.twig' %}
{% block column1 %}
... contents ...
{% endblock %}
!
{% block column2 %}
... contents ...
{% endblock %}
!
{% block column3 %}
... contents ...
{% endblock %}
{% endembed %}
When should you use {% embed %}
• To reuse page structures across different templates
(e.g. grids)
Lots of different ways to reuse templates
{% embed %} {% extends %}include()
{% set %} {% use %}macro()
Reusing fragments with {% set %}
{% set navigation %}
<a href="...">Previous</a>
...
...
<a href="...">Next</a>
{% endset %}
Reusing fragments with {% set %}
{% set navigation %}
<a href="...">Previous</a>
...
...
<a href="...">Next</a>
{% endset %} {{ navigation }}
{{ navigation }}
When should you use {% set %}
• To reuse short fragments of code inside a template
(if those fragments are configurable, use a macro).
• It's like an internal include() made from inside the
template itself.
Lots of different ways to reuse templates
{% embed %} {% extends %}include()
{% set %} {% use %}macro()
When should you use {% use %}
• This is too advanced and for very specific use
cases.
• You should probably never use it when creating
themes.
DYNAMIC
TEMPLATES
WHY IS THIS IMPORTANT??
Because Drupal allows to
create sites with very
advanced needs.
Templates created on-the-fly
{% set code = 'Hi {{ name }}' %}
{% set template = template_from_string(code) %}
!
{{ include(template) }}
Templates created on-the-fly
{% set code = 'Hi {{ name }}' %}
{% set template = template_from_string(code) %}
!
{{ include(template) }}
{% extends template %}
{% embed template %} It works here too
Templates created on-the-fly
{{ include(template_from_string(
'Hi {{ name }}'
)) }}
Templates created and modified on-the-fly
{% set code = 'Hi {{ name }}' %}
{% set code = code|replace({ 'Hi': 'Bye' }) %}
!
{% set template = template_from_string(code) %}
!
{{ include(template) }}
Getting the source of any template
{{ source('core/modules/block/templates/
block.html.twig') }}
It gets the source of the
given template without
actually rendering it.
Imagine a site which allows this customization
Section 1
Section 2
Default design
Customizable site
• Users can provide their own Twig snippets to
customize the design and content of some sections.
• Problem: even if customization is restricted to a
group of controlled users (e.g. "editors") you can't
trust those templates.
Twig Sandbox
• It's used to render "untrusted templates".
• It restricts the Twig features that can be used by the
template.
• Useful for letting users create their own templates
and maintain the application safe.
Twig Sandbox in practice
{% sandbox %}
{{ include(section.name ~ '/sidebar.twig') }}
{% endsandbox %}
!
!
{{ include(section.name ~ '/sidebar.twig',
sandboxed = true) }}
Twig Sandbox in practice
$policy = new Twig_Sandbox_SecurityPolicy(
$tags,
$filters,
$methods,
$properties,
$functions
);
!
$sandbox = new Twig_Extension_Sandbox($policy);
$twig->addExtension($sandbox);
Policy is defined as a
white-list of allowed
tags, filters, etc.
Twig Sandbox policy sample
$properties = array(
'label',
'configuration' => array('label', 'module'),
'block' => array('module'),
'attributes',
);
!
$policy = new Twig_Sandbox_SecurityPolicy(
$tags, $filters, $methods, $properties, $functions
);
DATES
WHY IS THIS IMPORTANT??
Because dealing with dates
is not easy and Twig can
perform a lot of operations
on dates.
Timezones support
{{ 'now'|date(timezone='Asia/Tokyo') }}
!
{{ 'now'|date(timezone=user.timezone) }}
Comparing dates
{% if event.startsAt > date('now') %}
Buy tickets
{% endif %}
Comparing dates
{% if event.startsAt > date('now') %}
Buy tickets
{% endif %}
NOTE This is the date( )
function, not the date filter
Modifying dates semantically
Early Bird ends at
{{ event.startsAt|date_modify('-15 days')|date }}
!
Confirm your sign up before
{{ user.createdAt|date_modify('+48 hours')|date }}
COOL
FEATURES
These are some of the
features that put Twig
years ahead of PHP
Useful filters for collections
{{ user.friends|first }}
{{ event.sessions|last }}
Useful tests for strings
{% if url starts with 'https://' %}
{% endif %}
!
{% if file_path ends with '.pdf' %}
{% endif %}
!
{% if phone matches '/^[d.]+$/' %}
{% endif %}
REJECTED BY
PHP
Useful tests for strings
{% if url starts with 'https://' %}
{% endif %}
!
{% if file_path ends with '.pdf' %}
{% endif %}
!
{% if phone matches '/^[d.]+$/' %}
{% endif %}
The "in" operator
{% if password in username %}
BAD PASSWORD
{% endif %}
!
{% if method in ['GET', 'POST'] %}
...
{% endif %}
The "in" operator
{% if password in username %}
BAD PASSWORD
{% endif %}
!
{% if method in ['GET', 'POST'] %}
...
{% endif %}
REJECTED BY
PHP
Named parameters
{{ content|convert_encoding('UTF-8', 'iso-2022-jp') }}
Named parameters
{{ content|convert_encoding('UTF-8', 'iso-2022-jp') }}
which is the original charset and
which one the target charset?
Named parameters
{{ content|convert_encoding('UTF-8', 'iso-2022-jp') }}
which is the original charset and
which one the target charset?
{{ content|convert_encoding(
from = 'UTF-8', to = 'iso-2022-jp'
) }}
Named parameters
{{ content|convert_encoding('UTF-8', 'iso-2022-jp') }}
which is the original charset and
which one the target charset?
{{ content|convert_encoding(
from = 'UTF-8', to = 'iso-2022-jp'
) }}
{{ content|convert_encoding(
to = 'UTF-8', from = 'iso-2022-jp'
) }}
Named parameters
{{ content|convert_encoding('UTF-8', 'iso-2022-jp') }}
PROPOSED FOR
PHP
which is the original charset and
which one the target charset?
{{ content|convert_encoding(
from = 'UTF-8', to = 'iso-2022-jp'
) }}
{{ content|convert_encoding(
to = 'UTF-8', from = 'iso-2022-jp'
) }}
Named parameters
{{ include('template.html', {}, true, true) }}
!
!
!
{{ include('template.html', ignore_missing = true) }}
template variables
with_context
ignore_missing
It's common to do things in batches
1
Image gallery
2 3
4 5 6
The HTML of the image gallery
<div class="row">
<div class="image"> ... </div>
<div class="image"> ... </div>
<div class="image"> ... </div>
</div>
!
<div class="row">
<div class="image"> ... </div>
<div class="image"> ... </div>
<div class="image"> ... </div>
</div>
The template without the "batch" filter
{% for i, image in images %}
{% if i is divisible by(3) %} <div class="row"> {% endif %}
!
<div class="image">
<img src="" alt="" >
<p>...</p>
</div>
!
{% if i is divisible by(3) %} </div> {% endif %}
{% endfor %}
The template without the "batch" filter
{% for i, image in images %}
{% if i is divisible by(3) %} <div class="row"> {% endif %}
!
<div class="image">
<img src="" alt="" >
<p>...</p>
</div>
!
{% if i is divisible by(3) %} </div> {% endif %}
{% endfor %}
UGLY CODE
The template with the "batch" filter
{% for row in images|batch(3) %}
<div class="row">
!
{% for image in row %}
<div class="image">
<img src="" alt="" >
<p>...</p>
</div>
{% endfor %}
!
</div>
{% endfor %}
The template with the "batch" filter
{% for row in images|batch(3) %}
<div class="row">
!
{% for image in row %}
<div class="image">
<img src="" alt="" >
<p>...</p>
</div>
{% endfor %}
!
</div>
{% endfor %}
Short ternary operator
$result = $condition ? 'is true';
Short ternary operator
$result = $condition ? 'is true';
ERROR Parse error: syntax error, unexpected ';' on line 1
Short ternary operator
$result = $condition ? 'is true';
ERROR Parse error: syntax error, unexpected ';' on line 1
{{ condition ? 'is true' }}
Short ternary operator
$result = $condition ? 'is true';
ERROR Parse error: syntax error, unexpected ';' on line 1
OK This works perfectly on Twig
{{ condition ? 'is true' }}
Short ternary operator
<li class="{{ condition ? 'selected' }}">
...
</li>
!
<li class="{{ condition ? 'selected' : '' }}">
...
</li>
Short ternary operator
<li class="{{ condition ? 'selected' }}">
...
</li>
!
<li class="{{ condition ? 'selected' : '' }}">
...
</li>
always use this
Short slice syntax
!
!
!
{{ user.friends[0:3] }}
{{ user.friends[:-3] }}
It combines array_slice, mb_substr
and substr PHP functions.
get first three friends
get last three friends
Short slice syntax
{{ '0123456789'[0:] }} {# 0123456789 #}
{{ '0123456789'[1:] }} {# 123456789 #}
{{ '0123456789'[20:] }} {# (empty) #}
{{ '0123456789'[-5:] }} {# 56789 #}
{{ '0123456789'[-1:] }} {# 9 #}
{{ '0123456789'[1:5] }} {# 12345 #}
{{ '0123456789'[1:-5] }} {# 1234 #}
OUTPUT
The "loop" magic variable
Everyone needs an $i variable inside
the for loop. So Twig provides you
this and other useful variables.
The "loop" variable exists only inside the "for"
{% for ... in collection %}
{{ loop.index }}
{{ loop.index0 }}
{{ loop.first }}
{{ loop.last }}
{{ loop.length }}
{% endfor %}
The "loop" variable exists only inside the "for"
{% for ... in collection %}
{{ loop.index }}
{{ loop.index0 }}
{{ loop.first }}
{{ loop.last }}
{{ loop.length }}
{% endfor %}
1, 2, 3, 4, 5, ...
0, 1, 2, 3, 4, ...
true, false, false, ...
..., false, false, true
5
{{ product.photo|image(400, 150, 0.9) }}
The problem with filter arguments
{{ product.photo|image(400, 150, 0.9) }}
The problem with filter arguments
What if I need to define more arguments?
{{ product.photo|image(400, 150, 0.9) }}
{{ product.photo|image(
width = 400, height = 150, opacity = 0.9
) }}
The problem with filter arguments
What if I need to define more arguments?
{{ product.photo|image(400, 150, 0.9) }}
{{ product.photo|image(
width = 400, height = 150, opacity = 0.9
) }}
The problem with filter arguments
What if I need to define more arguments?
this is a valid solution for Twig, but the
underlying PHP code is still very complex
Defining a filter with lots or arguments
$filter = new Twig_SimpleFilter('image', function (
$path, $width, $height, $opacity
) {
$path = ...
$width = ...
$height = ...
$opacity = ...
});
$filter = new Twig_SimpleFilter('image', function (
$path, $options = array()
) {
$path = ...
$width = $options['width'];
$height = $options['height'];
$opacity = $options['opacity'];
}, array('is_variadic' => true));
Defining a variadic filter
$filter = new Twig_SimpleFilter('image', function (
$path, $options = array()
) {
$path = ...
$width = $options['width'];
$height = $options['height'];
$opacity = $options['opacity'];
}, array('is_variadic' => true));
Defining a variadic filter
a single variadic parameter holds any
number of passed parameters (unlimited)
$filter = new Twig_SimpleFilter('image', function (
$path, $options = array()
) {
$path = ...
$width = $options['width'];
$height = $options['height'];
$opacity = $options['opacity'];
}, array('is_variadic' => true));
ACCEPTED BY
PHP
Defining a variadic filter
a single variadic parameter holds any
number of passed parameters (unlimited)
TO SUM UP
«Using Twig templates
is the best decision
Drupal ever made»
Drupal 8 templates are
safe, concise, modern
and consistent.
Twig
Drupal 8 templates are
safe, concise, modern
and consistent.
Drupal 8 themes
REFERENCES
References
• Official Twig documentation

twig.sensiolabs.org/documentation

• Twig in Drupal 8

drupal.org/theme-guide/8/twig
CONTACT
Contact info
• javier.eguiluz@sensiolabs.com
• github.com/javiereguiluz
• linkedin.com/in/javiereguiluz
!
!
!
Mastering Twig (DrupalCon Barcelona 2015)

Weitere ähnliche Inhalte

Was ist angesagt?

TWIG: the flexible, fast and secure template language for PHP
TWIG: the flexible, fast and secure template language for PHPTWIG: the flexible, fast and secure template language for PHP
TWIG: the flexible, fast and secure template language for PHPCesare D'Amico
 
Introduction to Twig
Introduction to TwigIntroduction to Twig
Introduction to Twigmarkstory
 
Symfony & Javascript. Combining the best of two worlds
Symfony & Javascript. Combining the best of two worldsSymfony & Javascript. Combining the best of two worlds
Symfony & Javascript. Combining the best of two worldsIgnacio Martín
 
Geek Moot '09 -- Smarty 101
Geek Moot '09 -- Smarty 101Geek Moot '09 -- Smarty 101
Geek Moot '09 -- Smarty 101Ted Kulp
 
Design Patterns in PHP5
Design Patterns in PHP5 Design Patterns in PHP5
Design Patterns in PHP5 Wildan Maulana
 
Object Oriented PHP5
Object Oriented PHP5Object Oriented PHP5
Object Oriented PHP5Jason Austin
 
10 PHP Design Patterns #burningkeyboards
10 PHP Design Patterns #burningkeyboards10 PHP Design Patterns #burningkeyboards
10 PHP Design Patterns #burningkeyboardsDenis Ristic
 
PHP Enums - PHPCon Japan 2021
PHP Enums - PHPCon Japan 2021PHP Enums - PHPCon Japan 2021
PHP Enums - PHPCon Japan 2021Ayesh Karunaratne
 
Dependency Injection with PHP 5.3
Dependency Injection with PHP 5.3Dependency Injection with PHP 5.3
Dependency Injection with PHP 5.3Fabien Potencier
 
Creating and Maintaining WordPress Plugins
Creating and Maintaining WordPress PluginsCreating and Maintaining WordPress Plugins
Creating and Maintaining WordPress PluginsMark Jaquith
 
Maintainable JavaScript 2012
Maintainable JavaScript 2012Maintainable JavaScript 2012
Maintainable JavaScript 2012Nicholas Zakas
 
Class 2 - Introduction to PHP
Class 2 - Introduction to PHPClass 2 - Introduction to PHP
Class 2 - Introduction to PHPAhmed Swilam
 
PHP: 4 Design Patterns to Make Better Code
PHP: 4 Design Patterns to Make Better CodePHP: 4 Design Patterns to Make Better Code
PHP: 4 Design Patterns to Make Better CodeSWIFTotter Solutions
 
PHP 8.1 - What's new and changed
PHP 8.1 - What's new and changedPHP 8.1 - What's new and changed
PHP 8.1 - What's new and changedAyesh Karunaratne
 

Was ist angesagt? (19)

TWIG: the flexible, fast and secure template language for PHP
TWIG: the flexible, fast and secure template language for PHPTWIG: the flexible, fast and secure template language for PHP
TWIG: the flexible, fast and secure template language for PHP
 
Codeware
CodewareCodeware
Codeware
 
Introduction to Twig
Introduction to TwigIntroduction to Twig
Introduction to Twig
 
Design patterns in PHP
Design patterns in PHPDesign patterns in PHP
Design patterns in PHP
 
Symfony & Javascript. Combining the best of two worlds
Symfony & Javascript. Combining the best of two worldsSymfony & Javascript. Combining the best of two worlds
Symfony & Javascript. Combining the best of two worlds
 
Geek Moot '09 -- Smarty 101
Geek Moot '09 -- Smarty 101Geek Moot '09 -- Smarty 101
Geek Moot '09 -- Smarty 101
 
Design Patterns in PHP5
Design Patterns in PHP5 Design Patterns in PHP5
Design Patterns in PHP5
 
Object Oriented PHP5
Object Oriented PHP5Object Oriented PHP5
Object Oriented PHP5
 
Functions in PHP
Functions in PHPFunctions in PHP
Functions in PHP
 
Php Tutorials for Beginners
Php Tutorials for BeginnersPhp Tutorials for Beginners
Php Tutorials for Beginners
 
10 PHP Design Patterns #burningkeyboards
10 PHP Design Patterns #burningkeyboards10 PHP Design Patterns #burningkeyboards
10 PHP Design Patterns #burningkeyboards
 
PHP Enums - PHPCon Japan 2021
PHP Enums - PHPCon Japan 2021PHP Enums - PHPCon Japan 2021
PHP Enums - PHPCon Japan 2021
 
Dependency Injection with PHP 5.3
Dependency Injection with PHP 5.3Dependency Injection with PHP 5.3
Dependency Injection with PHP 5.3
 
Data Validation models
Data Validation modelsData Validation models
Data Validation models
 
Creating and Maintaining WordPress Plugins
Creating and Maintaining WordPress PluginsCreating and Maintaining WordPress Plugins
Creating and Maintaining WordPress Plugins
 
Maintainable JavaScript 2012
Maintainable JavaScript 2012Maintainable JavaScript 2012
Maintainable JavaScript 2012
 
Class 2 - Introduction to PHP
Class 2 - Introduction to PHPClass 2 - Introduction to PHP
Class 2 - Introduction to PHP
 
PHP: 4 Design Patterns to Make Better Code
PHP: 4 Design Patterns to Make Better CodePHP: 4 Design Patterns to Make Better Code
PHP: 4 Design Patterns to Make Better Code
 
PHP 8.1 - What's new and changed
PHP 8.1 - What's new and changedPHP 8.1 - What's new and changed
PHP 8.1 - What's new and changed
 

Andere mochten auch

New Symfony Tips & Tricks (SymfonyCon Paris 2015)
New Symfony Tips & Tricks (SymfonyCon Paris 2015)New Symfony Tips & Tricks (SymfonyCon Paris 2015)
New Symfony Tips & Tricks (SymfonyCon Paris 2015)Javier Eguiluz
 
Twig, el nuevo motor de plantillas de Drupal 8
Twig, el nuevo motor de plantillas de Drupal 8Twig, el nuevo motor de plantillas de Drupal 8
Twig, el nuevo motor de plantillas de Drupal 8Javier Eguiluz
 
Symfony tips and tricks
Symfony tips and tricksSymfony tips and tricks
Symfony tips and tricksJavier Eguiluz
 
Twig, los mejores trucos y técnicas avanzadas
Twig, los mejores trucos y técnicas avanzadasTwig, los mejores trucos y técnicas avanzadas
Twig, los mejores trucos y técnicas avanzadasJavier Eguiluz
 
Arquitectura para artesanos
Arquitectura para artesanosArquitectura para artesanos
Arquitectura para artesanosatassani
 
Software craftsmanship coaching
Software craftsmanship coachingSoftware craftsmanship coaching
Software craftsmanship coachingPedro Santos
 
#PhpirstAid - Replanteamiento de diseño de software
#PhpirstAid - Replanteamiento de diseño de software#PhpirstAid - Replanteamiento de diseño de software
#PhpirstAid - Replanteamiento de diseño de softwareJavier Ferrer González
 
Introduzione a JavaScript
Introduzione a JavaScriptIntroduzione a JavaScript
Introduzione a JavaScriptGiovanni Buffa
 
Have you played this Symfony? Why Symfony is great choice for Web development
Have you played this Symfony? Why Symfony is great choice for Web developmentHave you played this Symfony? Why Symfony is great choice for Web development
Have you played this Symfony? Why Symfony is great choice for Web developmentMike Taylor
 
Symfony2: 30 astuces et bonnes pratiques
Symfony2: 30 astuces et bonnes pratiquesSymfony2: 30 astuces et bonnes pratiques
Symfony2: 30 astuces et bonnes pratiquesNoel GUILBERT
 
Design patterns avec Symfony
Design patterns avec SymfonyDesign patterns avec Symfony
Design patterns avec SymfonyMohammed Rhamnia
 
Angular js o React? Spunti e idee per la scelta di un framework
Angular js o React? Spunti e idee per la scelta di un frameworkAngular js o React? Spunti e idee per la scelta di un framework
Angular js o React? Spunti e idee per la scelta di un frameworkGiovanni Buffa
 
SymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years later
SymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years laterSymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years later
SymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years laterHaehnchen
 
Hexagonal architecture - message-oriented software design
Hexagonal architecture  - message-oriented software designHexagonal architecture  - message-oriented software design
Hexagonal architecture - message-oriented software designMatthias Noback
 
sfDay Cologne - Sonata Admin Bundle
sfDay Cologne - Sonata Admin BundlesfDay Cologne - Sonata Admin Bundle
sfDay Cologne - Sonata Admin Bundleth0masr
 

Andere mochten auch (20)

New Symfony Tips & Tricks (SymfonyCon Paris 2015)
New Symfony Tips & Tricks (SymfonyCon Paris 2015)New Symfony Tips & Tricks (SymfonyCon Paris 2015)
New Symfony Tips & Tricks (SymfonyCon Paris 2015)
 
Twig, el nuevo motor de plantillas de Drupal 8
Twig, el nuevo motor de plantillas de Drupal 8Twig, el nuevo motor de plantillas de Drupal 8
Twig, el nuevo motor de plantillas de Drupal 8
 
Symfony tips and tricks
Symfony tips and tricksSymfony tips and tricks
Symfony tips and tricks
 
Symfony Best Practices
Symfony Best PracticesSymfony Best Practices
Symfony Best Practices
 
30 Symfony Best Practices
30 Symfony Best Practices30 Symfony Best Practices
30 Symfony Best Practices
 
Twig, los mejores trucos y técnicas avanzadas
Twig, los mejores trucos y técnicas avanzadasTwig, los mejores trucos y técnicas avanzadas
Twig, los mejores trucos y técnicas avanzadas
 
Arquitectura para artesanos
Arquitectura para artesanosArquitectura para artesanos
Arquitectura para artesanos
 
Php 101: PDO
Php 101: PDOPhp 101: PDO
Php 101: PDO
 
Software craftsmanship coaching
Software craftsmanship coachingSoftware craftsmanship coaching
Software craftsmanship coaching
 
#PhpirstAid - Replanteamiento de diseño de software
#PhpirstAid - Replanteamiento de diseño de software#PhpirstAid - Replanteamiento de diseño de software
#PhpirstAid - Replanteamiento de diseño de software
 
JavaScript
JavaScriptJavaScript
JavaScript
 
Introduzione a JavaScript
Introduzione a JavaScriptIntroduzione a JavaScript
Introduzione a JavaScript
 
Have you played this Symfony? Why Symfony is great choice for Web development
Have you played this Symfony? Why Symfony is great choice for Web developmentHave you played this Symfony? Why Symfony is great choice for Web development
Have you played this Symfony? Why Symfony is great choice for Web development
 
Symfony2: 30 astuces et bonnes pratiques
Symfony2: 30 astuces et bonnes pratiquesSymfony2: 30 astuces et bonnes pratiques
Symfony2: 30 astuces et bonnes pratiques
 
Design patterns avec Symfony
Design patterns avec SymfonyDesign patterns avec Symfony
Design patterns avec Symfony
 
Angular js o React? Spunti e idee per la scelta di un framework
Angular js o React? Spunti e idee per la scelta di un frameworkAngular js o React? Spunti e idee per la scelta di un framework
Angular js o React? Spunti e idee per la scelta di un framework
 
Symfony Components
Symfony ComponentsSymfony Components
Symfony Components
 
SymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years later
SymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years laterSymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years later
SymfonyCon Berlin 2016 - Symfony Plugin for PhpStorm - 3 years later
 
Hexagonal architecture - message-oriented software design
Hexagonal architecture  - message-oriented software designHexagonal architecture  - message-oriented software design
Hexagonal architecture - message-oriented software design
 
sfDay Cologne - Sonata Admin Bundle
sfDay Cologne - Sonata Admin BundlesfDay Cologne - Sonata Admin Bundle
sfDay Cologne - Sonata Admin Bundle
 

Ähnlich wie Mastering Twig (DrupalCon Barcelona 2015)

Twig: Friendly Curly Braces Invade Your Templates!
Twig: Friendly Curly Braces Invade Your Templates!Twig: Friendly Curly Braces Invade Your Templates!
Twig: Friendly Curly Braces Invade Your Templates!Ryan Weaver
 
Drupalcamp Leuven 2013 - Display Suite, the future of your display
Drupalcamp Leuven 2013 - Display Suite, the future of your displayDrupalcamp Leuven 2013 - Display Suite, the future of your display
Drupalcamp Leuven 2013 - Display Suite, the future of your displayBram Goffings
 
Being Dangerous with Twig
Being Dangerous with TwigBeing Dangerous with Twig
Being Dangerous with TwigRyan Weaver
 
Presentation drupalaton august 2013
Presentation drupalaton august 2013Presentation drupalaton august 2013
Presentation drupalaton august 2013Bram Goffings
 
Presentation drupalaton, August 2013
Presentation drupalaton, August 2013Presentation drupalaton, August 2013
Presentation drupalaton, August 2013Nascom
 
Being Dangerous with Twig (Symfony Live Paris)
Being Dangerous with Twig (Symfony Live Paris)Being Dangerous with Twig (Symfony Live Paris)
Being Dangerous with Twig (Symfony Live Paris)Ryan Weaver
 
The state of Symfony2 - SymfonyDay 2010
The state of Symfony2 - SymfonyDay 2010The state of Symfony2 - SymfonyDay 2010
The state of Symfony2 - SymfonyDay 2010Fabien Potencier
 
Grails Worst Practices
Grails Worst PracticesGrails Worst Practices
Grails Worst PracticesBurt Beckwith
 
Powerful and flexible templates with Twig
Powerful and flexible templates with Twig Powerful and flexible templates with Twig
Powerful and flexible templates with Twig Michael Peacock
 
Twig for Drupal 8 and PHP | Presented at OC Drupal
Twig for Drupal 8 and PHP | Presented at OC DrupalTwig for Drupal 8 and PHP | Presented at OC Drupal
Twig for Drupal 8 and PHP | Presented at OC Drupalwebbywe
 
Enhance your WordPress development with Twig through Clarkson - WordCamp Barc...
Enhance your WordPress development with Twig through Clarkson - WordCamp Barc...Enhance your WordPress development with Twig through Clarkson - WordCamp Barc...
Enhance your WordPress development with Twig through Clarkson - WordCamp Barc...Jaime Martínez
 
Micropatterns
MicropatternsMicropatterns
Micropatternscameronp
 
Symfony 4 Workshop - Limenius
Symfony 4 Workshop - LimeniusSymfony 4 Workshop - Limenius
Symfony 4 Workshop - LimeniusIgnacio Martín
 
Twig for Drupal @ Frontendunited Amsterdam 2012
Twig for Drupal @ Frontendunited Amsterdam 2012Twig for Drupal @ Frontendunited Amsterdam 2012
Twig for Drupal @ Frontendunited Amsterdam 2012Rene Bakx
 

Ähnlich wie Mastering Twig (DrupalCon Barcelona 2015) (20)

Twig: Friendly Curly Braces Invade Your Templates!
Twig: Friendly Curly Braces Invade Your Templates!Twig: Friendly Curly Braces Invade Your Templates!
Twig: Friendly Curly Braces Invade Your Templates!
 
Drupalcamp Leuven 2013 - Display Suite, the future of your display
Drupalcamp Leuven 2013 - Display Suite, the future of your displayDrupalcamp Leuven 2013 - Display Suite, the future of your display
Drupalcamp Leuven 2013 - Display Suite, the future of your display
 
Being Dangerous with Twig
Being Dangerous with TwigBeing Dangerous with Twig
Being Dangerous with Twig
 
Presentation drupalaton august 2013
Presentation drupalaton august 2013Presentation drupalaton august 2013
Presentation drupalaton august 2013
 
Presentation drupalaton, August 2013
Presentation drupalaton, August 2013Presentation drupalaton, August 2013
Presentation drupalaton, August 2013
 
Being Dangerous with Twig (Symfony Live Paris)
Being Dangerous with Twig (Symfony Live Paris)Being Dangerous with Twig (Symfony Live Paris)
Being Dangerous with Twig (Symfony Live Paris)
 
The state of Symfony2 - SymfonyDay 2010
The state of Symfony2 - SymfonyDay 2010The state of Symfony2 - SymfonyDay 2010
The state of Symfony2 - SymfonyDay 2010
 
Grails Worst Practices
Grails Worst PracticesGrails Worst Practices
Grails Worst Practices
 
Into The Box 2018 - CBT
Into The Box 2018 - CBTInto The Box 2018 - CBT
Into The Box 2018 - CBT
 
Powerful and flexible templates with Twig
Powerful and flexible templates with Twig Powerful and flexible templates with Twig
Powerful and flexible templates with Twig
 
Pruexx User's guide for beta testing
Pruexx User's guide for beta testingPruexx User's guide for beta testing
Pruexx User's guide for beta testing
 
Web-First Design Patterns
Web-First Design PatternsWeb-First Design Patterns
Web-First Design Patterns
 
Twig for Drupal 8 and PHP | Presented at OC Drupal
Twig for Drupal 8 and PHP | Presented at OC DrupalTwig for Drupal 8 and PHP | Presented at OC Drupal
Twig for Drupal 8 and PHP | Presented at OC Drupal
 
Enhance your WordPress development with Twig through Clarkson - WordCamp Barc...
Enhance your WordPress development with Twig through Clarkson - WordCamp Barc...Enhance your WordPress development with Twig through Clarkson - WordCamp Barc...
Enhance your WordPress development with Twig through Clarkson - WordCamp Barc...
 
Micropatterns
MicropatternsMicropatterns
Micropatterns
 
Twig
TwigTwig
Twig
 
Symfony 4 Workshop - Limenius
Symfony 4 Workshop - LimeniusSymfony 4 Workshop - Limenius
Symfony 4 Workshop - Limenius
 
Twig for Drupal @ Frontendunited Amsterdam 2012
Twig for Drupal @ Frontendunited Amsterdam 2012Twig for Drupal @ Frontendunited Amsterdam 2012
Twig for Drupal @ Frontendunited Amsterdam 2012
 
Mastering Drupal 8’s Twig
Mastering Drupal 8’s TwigMastering Drupal 8’s Twig
Mastering Drupal 8’s Twig
 
Metaprogramming
MetaprogrammingMetaprogramming
Metaprogramming
 

Mehr von Javier Eguiluz

deSymfony 2017: Symfony 4, Symfony Flex y el futuro de Symfony
deSymfony 2017: Symfony 4, Symfony Flex y el futuro de SymfonydeSymfony 2017: Symfony 4, Symfony Flex y el futuro de Symfony
deSymfony 2017: Symfony 4, Symfony Flex y el futuro de SymfonyJavier Eguiluz
 
Silex, desarrollo web ágil y profesional con PHP
Silex, desarrollo web ágil y profesional con PHPSilex, desarrollo web ágil y profesional con PHP
Silex, desarrollo web ágil y profesional con PHPJavier Eguiluz
 
Twig avanzado (sf2Vigo)
Twig avanzado (sf2Vigo)Twig avanzado (sf2Vigo)
Twig avanzado (sf2Vigo)Javier Eguiluz
 
Desymfony 2012 - Concurso de diseño
Desymfony 2012 - Concurso de diseñoDesymfony 2012 - Concurso de diseño
Desymfony 2012 - Concurso de diseñoJavier Eguiluz
 
Desymfony 2011 - Tutorial #5: Backend
Desymfony 2011 - Tutorial #5: BackendDesymfony 2011 - Tutorial #5: Backend
Desymfony 2011 - Tutorial #5: BackendJavier Eguiluz
 
Desymfony 2011 - Tutorial #1: Instalacion y primeros pasos
Desymfony 2011 - Tutorial #1: Instalacion y primeros pasosDesymfony 2011 - Tutorial #1: Instalacion y primeros pasos
Desymfony 2011 - Tutorial #1: Instalacion y primeros pasosJavier Eguiluz
 
Desymfony 2011 - Introducción a Symfony2
Desymfony 2011 - Introducción a Symfony2Desymfony 2011 - Introducción a Symfony2
Desymfony 2011 - Introducción a Symfony2Javier Eguiluz
 
Symfony2, Jornadas Symfony
Symfony2, Jornadas SymfonySymfony2, Jornadas Symfony
Symfony2, Jornadas SymfonyJavier Eguiluz
 
Curso Symfony - Anexos
Curso Symfony - AnexosCurso Symfony - Anexos
Curso Symfony - AnexosJavier Eguiluz
 
Curso Symfony - Clase 5
Curso Symfony - Clase 5Curso Symfony - Clase 5
Curso Symfony - Clase 5Javier Eguiluz
 
Curso Symfony - Clase 4
Curso Symfony - Clase 4Curso Symfony - Clase 4
Curso Symfony - Clase 4Javier Eguiluz
 
Curso Symfony - Clase 3
Curso Symfony - Clase 3Curso Symfony - Clase 3
Curso Symfony - Clase 3Javier Eguiluz
 
Curso Symfony - Clase 2
Curso Symfony - Clase 2Curso Symfony - Clase 2
Curso Symfony - Clase 2Javier Eguiluz
 
Curso Symfony - Clase 1
Curso Symfony - Clase 1Curso Symfony - Clase 1
Curso Symfony - Clase 1Javier Eguiluz
 

Mehr von Javier Eguiluz (18)

deSymfony 2017: Symfony 4, Symfony Flex y el futuro de Symfony
deSymfony 2017: Symfony 4, Symfony Flex y el futuro de SymfonydeSymfony 2017: Symfony 4, Symfony Flex y el futuro de Symfony
deSymfony 2017: Symfony 4, Symfony Flex y el futuro de Symfony
 
Silex al límite
Silex al límiteSilex al límite
Silex al límite
 
Silex, desarrollo web ágil y profesional con PHP
Silex, desarrollo web ágil y profesional con PHPSilex, desarrollo web ágil y profesional con PHP
Silex, desarrollo web ágil y profesional con PHP
 
Wallpaper Notifier
Wallpaper NotifierWallpaper Notifier
Wallpaper Notifier
 
Backend (sf2Vigo)
Backend (sf2Vigo)Backend (sf2Vigo)
Backend (sf2Vigo)
 
Twig avanzado (sf2Vigo)
Twig avanzado (sf2Vigo)Twig avanzado (sf2Vigo)
Twig avanzado (sf2Vigo)
 
Desymfony 2012 - Concurso de diseño
Desymfony 2012 - Concurso de diseñoDesymfony 2012 - Concurso de diseño
Desymfony 2012 - Concurso de diseño
 
Desymfony 2011 - Twig
Desymfony 2011 - TwigDesymfony 2011 - Twig
Desymfony 2011 - Twig
 
Desymfony 2011 - Tutorial #5: Backend
Desymfony 2011 - Tutorial #5: BackendDesymfony 2011 - Tutorial #5: Backend
Desymfony 2011 - Tutorial #5: Backend
 
Desymfony 2011 - Tutorial #1: Instalacion y primeros pasos
Desymfony 2011 - Tutorial #1: Instalacion y primeros pasosDesymfony 2011 - Tutorial #1: Instalacion y primeros pasos
Desymfony 2011 - Tutorial #1: Instalacion y primeros pasos
 
Desymfony 2011 - Introducción a Symfony2
Desymfony 2011 - Introducción a Symfony2Desymfony 2011 - Introducción a Symfony2
Desymfony 2011 - Introducción a Symfony2
 
Symfony2, Jornadas Symfony
Symfony2, Jornadas SymfonySymfony2, Jornadas Symfony
Symfony2, Jornadas Symfony
 
Curso Symfony - Anexos
Curso Symfony - AnexosCurso Symfony - Anexos
Curso Symfony - Anexos
 
Curso Symfony - Clase 5
Curso Symfony - Clase 5Curso Symfony - Clase 5
Curso Symfony - Clase 5
 
Curso Symfony - Clase 4
Curso Symfony - Clase 4Curso Symfony - Clase 4
Curso Symfony - Clase 4
 
Curso Symfony - Clase 3
Curso Symfony - Clase 3Curso Symfony - Clase 3
Curso Symfony - Clase 3
 
Curso Symfony - Clase 2
Curso Symfony - Clase 2Curso Symfony - Clase 2
Curso Symfony - Clase 2
 
Curso Symfony - Clase 1
Curso Symfony - Clase 1Curso Symfony - Clase 1
Curso Symfony - Clase 1
 

Kürzlich hochgeladen

Infrared simulation and processing on Nvidia platforms
Infrared simulation and processing on Nvidia platformsInfrared simulation and processing on Nvidia platforms
Infrared simulation and processing on Nvidia platformsYoss Cohen
 
A Framework for Development in the AI Age
A Framework for Development in the AI AgeA Framework for Development in the AI Age
A Framework for Development in the AI AgeCprime
 
Landscape Catalogue 2024 Australia-1.pdf
Landscape Catalogue 2024 Australia-1.pdfLandscape Catalogue 2024 Australia-1.pdf
Landscape Catalogue 2024 Australia-1.pdfAarwolf Industries LLC
 
Generative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdfGenerative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdfIngrid Airi González
 
Tampa BSides - The No BS SOC (slides from April 6, 2024 talk)
Tampa BSides - The No BS SOC (slides from April 6, 2024 talk)Tampa BSides - The No BS SOC (slides from April 6, 2024 talk)
Tampa BSides - The No BS SOC (slides from April 6, 2024 talk)Mark Simos
 
4. Cobus Valentine- Cybersecurity Threats and Solutions for the Public Sector
4. Cobus Valentine- Cybersecurity Threats and Solutions for the Public Sector4. Cobus Valentine- Cybersecurity Threats and Solutions for the Public Sector
4. Cobus Valentine- Cybersecurity Threats and Solutions for the Public Sectoritnewsafrica
 
Design pattern talk by Kaya Weers - 2024 (v2)
Design pattern talk by Kaya Weers - 2024 (v2)Design pattern talk by Kaya Weers - 2024 (v2)
Design pattern talk by Kaya Weers - 2024 (v2)Kaya Weers
 
QCon London: Mastering long-running processes in modern architectures
QCon London: Mastering long-running processes in modern architecturesQCon London: Mastering long-running processes in modern architectures
QCon London: Mastering long-running processes in modern architecturesBernd Ruecker
 
Microservices, Docker deploy and Microservices source code in C#
Microservices, Docker deploy and Microservices source code in C#Microservices, Docker deploy and Microservices source code in C#
Microservices, Docker deploy and Microservices source code in C#Karmanjay Verma
 
Generative AI - Gitex v1Generative AI - Gitex v1.pptx
Generative AI - Gitex v1Generative AI - Gitex v1.pptxGenerative AI - Gitex v1Generative AI - Gitex v1.pptx
Generative AI - Gitex v1Generative AI - Gitex v1.pptxfnnc6jmgwh
 
Top 10 Hubspot Development Companies in 2024
Top 10 Hubspot Development Companies in 2024Top 10 Hubspot Development Companies in 2024
Top 10 Hubspot Development Companies in 2024TopCSSGallery
 
Bridging Between CAD & GIS: 6 Ways to Automate Your Data Integration
Bridging Between CAD & GIS:  6 Ways to Automate Your Data IntegrationBridging Between CAD & GIS:  6 Ways to Automate Your Data Integration
Bridging Between CAD & GIS: 6 Ways to Automate Your Data Integrationmarketing932765
 
Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Hiroshi SHIBATA
 
MuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotes
MuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotesMuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotes
MuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotesManik S Magar
 
Kuma Meshes Part I - The basics - A tutorial
Kuma Meshes Part I - The basics - A tutorialKuma Meshes Part I - The basics - A tutorial
Kuma Meshes Part I - The basics - A tutorialJoão Esperancinha
 
Microsoft 365 Copilot: How to boost your productivity with AI – Part two: Dat...
Microsoft 365 Copilot: How to boost your productivity with AI – Part two: Dat...Microsoft 365 Copilot: How to boost your productivity with AI – Part two: Dat...
Microsoft 365 Copilot: How to boost your productivity with AI – Part two: Dat...Nikki Chapple
 
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...Wes McKinney
 
Accelerating Enterprise Software Engineering with Platformless
Accelerating Enterprise Software Engineering with PlatformlessAccelerating Enterprise Software Engineering with Platformless
Accelerating Enterprise Software Engineering with PlatformlessWSO2
 
React JS; all concepts. Contains React Features, JSX, functional & Class comp...
React JS; all concepts. Contains React Features, JSX, functional & Class comp...React JS; all concepts. Contains React Features, JSX, functional & Class comp...
React JS; all concepts. Contains React Features, JSX, functional & Class comp...Karmanjay Verma
 
Irene Moetsana-Moeng: Stakeholders in Cybersecurity: Collaborative Defence fo...
Irene Moetsana-Moeng: Stakeholders in Cybersecurity: Collaborative Defence fo...Irene Moetsana-Moeng: Stakeholders in Cybersecurity: Collaborative Defence fo...
Irene Moetsana-Moeng: Stakeholders in Cybersecurity: Collaborative Defence fo...itnewsafrica
 

Kürzlich hochgeladen (20)

Infrared simulation and processing on Nvidia platforms
Infrared simulation and processing on Nvidia platformsInfrared simulation and processing on Nvidia platforms
Infrared simulation and processing on Nvidia platforms
 
A Framework for Development in the AI Age
A Framework for Development in the AI AgeA Framework for Development in the AI Age
A Framework for Development in the AI Age
 
Landscape Catalogue 2024 Australia-1.pdf
Landscape Catalogue 2024 Australia-1.pdfLandscape Catalogue 2024 Australia-1.pdf
Landscape Catalogue 2024 Australia-1.pdf
 
Generative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdfGenerative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdf
 
Tampa BSides - The No BS SOC (slides from April 6, 2024 talk)
Tampa BSides - The No BS SOC (slides from April 6, 2024 talk)Tampa BSides - The No BS SOC (slides from April 6, 2024 talk)
Tampa BSides - The No BS SOC (slides from April 6, 2024 talk)
 
4. Cobus Valentine- Cybersecurity Threats and Solutions for the Public Sector
4. Cobus Valentine- Cybersecurity Threats and Solutions for the Public Sector4. Cobus Valentine- Cybersecurity Threats and Solutions for the Public Sector
4. Cobus Valentine- Cybersecurity Threats and Solutions for the Public Sector
 
Design pattern talk by Kaya Weers - 2024 (v2)
Design pattern talk by Kaya Weers - 2024 (v2)Design pattern talk by Kaya Weers - 2024 (v2)
Design pattern talk by Kaya Weers - 2024 (v2)
 
QCon London: Mastering long-running processes in modern architectures
QCon London: Mastering long-running processes in modern architecturesQCon London: Mastering long-running processes in modern architectures
QCon London: Mastering long-running processes in modern architectures
 
Microservices, Docker deploy and Microservices source code in C#
Microservices, Docker deploy and Microservices source code in C#Microservices, Docker deploy and Microservices source code in C#
Microservices, Docker deploy and Microservices source code in C#
 
Generative AI - Gitex v1Generative AI - Gitex v1.pptx
Generative AI - Gitex v1Generative AI - Gitex v1.pptxGenerative AI - Gitex v1Generative AI - Gitex v1.pptx
Generative AI - Gitex v1Generative AI - Gitex v1.pptx
 
Top 10 Hubspot Development Companies in 2024
Top 10 Hubspot Development Companies in 2024Top 10 Hubspot Development Companies in 2024
Top 10 Hubspot Development Companies in 2024
 
Bridging Between CAD & GIS: 6 Ways to Automate Your Data Integration
Bridging Between CAD & GIS:  6 Ways to Automate Your Data IntegrationBridging Between CAD & GIS:  6 Ways to Automate Your Data Integration
Bridging Between CAD & GIS: 6 Ways to Automate Your Data Integration
 
Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024
 
MuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotes
MuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotesMuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotes
MuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotes
 
Kuma Meshes Part I - The basics - A tutorial
Kuma Meshes Part I - The basics - A tutorialKuma Meshes Part I - The basics - A tutorial
Kuma Meshes Part I - The basics - A tutorial
 
Microsoft 365 Copilot: How to boost your productivity with AI – Part two: Dat...
Microsoft 365 Copilot: How to boost your productivity with AI – Part two: Dat...Microsoft 365 Copilot: How to boost your productivity with AI – Part two: Dat...
Microsoft 365 Copilot: How to boost your productivity with AI – Part two: Dat...
 
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
 
Accelerating Enterprise Software Engineering with Platformless
Accelerating Enterprise Software Engineering with PlatformlessAccelerating Enterprise Software Engineering with Platformless
Accelerating Enterprise Software Engineering with Platformless
 
React JS; all concepts. Contains React Features, JSX, functional & Class comp...
React JS; all concepts. Contains React Features, JSX, functional & Class comp...React JS; all concepts. Contains React Features, JSX, functional & Class comp...
React JS; all concepts. Contains React Features, JSX, functional & Class comp...
 
Irene Moetsana-Moeng: Stakeholders in Cybersecurity: Collaborative Defence fo...
Irene Moetsana-Moeng: Stakeholders in Cybersecurity: Collaborative Defence fo...Irene Moetsana-Moeng: Stakeholders in Cybersecurity: Collaborative Defence fo...
Irene Moetsana-Moeng: Stakeholders in Cybersecurity: Collaborative Defence fo...
 

Mastering Twig (DrupalCon Barcelona 2015)

  • 1. Javier EguiluzSeptember 22, 2015 Twig TRACK ROOM DATE SPEAKER Symfony 115 Mastering
  • 2. License of this presentation creativecommons.org/licenses/by-nc-sa/3.0
  • 6. We won't talk about Twig basics. We won't provide all the low-level details. How can I create a theme? Which is the syntax of Twig? Read the excellent Twig documentation to get those details.
  • 8. Fast Easy to learn Documented Concise Full featured Extensible Tested Useful errors Secure Main Twig features
  • 10. My favorite feature Twig defines a very small set of features… … which are enough to create any template Consistent same syntax and behavior since day one! easy to learn!
  • 11. «Using Twig templates is the best decision Drupal ever made»
  • 12. DRUPAL 8 TWIG Built-in Drupal templates use ~30% of the available Twig features.
  • 16. WHY IS THIS IMPORTANT?? Because you can easily improve the performance of your site/app.
  • 17. Accessing simple variables ! <p class="comment__author">{{ author }}</p> <p class="comment__time">{{ created }}</p> <p class="comment__permalink">{{ permalink }}</p> core/themes/bartik/templates/comment.html.twig
  • 18. Accessing complex variables ! <nav>{{ content.links }}</nav> core/themes/bartik/templates/comment.html.twig
  • 19. Accessing complex variables ! <nav>{{ content.links }}</nav> core/themes/bartik/templates/comment.html.twig
  • 20. This is how Twig resolves complex variables <nav>{{ content.links }}</nav> ! $content['links'] $content->links $content->links() $content->getLinks() $content->isLinks() null Twig tries all these alternatives and uses the first one that exists.
  • 22. Resolving variables is quite expensive <nav>{{ content.links }}</nav> ! $content['links'] $content->links $content->links() $content->getLinks() $content->isLinks() null Resolving a variable is the most expensive Twig task, specially for very complex templates.
  • 23. Improving Twig performance • Twig provides a PHP extension. • This extension only implements the variable resolving logic. • See twig.sensiolabs.org/doc/ installation.html#installing-the- c-extension EXPECTED
 PERFORMANCE INCREASE 15%
  • 24. Some Drupal variables names are special ! $variables['site_slogan']['#markup'] = ... ! {{ site_slogan.#markup }} core/themes/bartik/bartik.theme This doesn't work because of the # character
  • 25. Some Drupal variables names are special ! $variables['site_slogan']['#markup'] = ... ! {{ site_slogan.#markup }} core/themes/bartik/bartik.theme This doesn't work because of the # character {{ site_slogan['#markup'] }} {{ attribute(site_slogan, '#markup') }}
  • 27. WHY IS THIS IMPORTANT?? Because sooner or later errors will happen. What matters is how you deal with them.
  • 28. Dealing with undefined/empty variables is empty defaultis defined is null {% if %}
  • 29. The two recommended safeguards {% if variable %} ... {% endif %} ! ! Hi {{ variable|default('user') }}
  • 30. The two recommended safeguards {% if variable %} ... {% endif %} ! ! Hi {{ variable|default('user') }} It checks that variable is not null or empty or zero ! ONLY works if variable is defined
  • 31. The two recommended safeguards {% if variable %} ... {% endif %} ! ! Hi {{ variable|default('user') }} It checks that variable is not null or empty or zero ! ONLY works if variable is defined It checks that variable is not null, empty or undefined ! It ALWAYS works as expected
  • 32. Combining both safeguards {% if variable|default('user') %} ... {% endif %} It doesn't matter if the variable is not defined, because the expression will always have a default value.
  • 33. Checking that the variable is defined {% if variable is defined %} ... {% endif %} A good practice when the rendered template cannot be sure about the variables passed from the code. ! In Drupal 8 this problem should not happen (the variable list is strict).
  • 34. Other safeguards available {% if variable is null %} ... {% endif %} ! ! {% if variable is empty %} ... {% endif %} {% if variable is not empty %} ... {% endif %}
  • 35. Be ready when iterating empty collections {% for item in collection %} ... {% else %} There are no items. {% endfor %}
  • 36. Filter values before using them in the loop {% for item in collection if item.published %} ... {% else %} There are no items. {% endfor %}
  • 37. Avoid missing templates {{ include('menu.twig') }} This will always work because our theme will provide this template.
  • 38. Avoid missing templates {{ include('menu.twig') }} This will always work because our theme will provide this template. Templates with dynamic paths are very prone to error {{ include('users/' ~ user.name ~ '/bio.twig') }}
  • 39. Define fallback templates {{ include([ 'users/' ~ user.name ~ '/bio.twig', 'users/' ~ user.name ~ '/default.twig', 'common/user_bio.twig' ]) }} Twig includes the first template that exists
  • 40. Avoid missing templates • Sometimes it's not possible to provide fallback templates. • Moreover, in some cases, it's better to ignore the missing template instead of displaying an error to the user.
  • 41. Ignore missing templates {{ include('template.twig', ignore_missing = true) }} ! {{ source('template.twig', ignore_missing = true) }} ! {% embed 'template.twig' ignore missing %} ... {% endembed %}
  • 42. Ignore missing templates {{ include('template.twig', ignore_missing = true) }} ! {{ source('template.twig', ignore_missing = true) }} ! {% embed 'template.twig' ignore missing %} ... {% endembed %} NOTE no underscore here
  • 43. Twig filters defined by Drupal 8 {{ value|t }} {{ value|trans }} {{ value|passthrough }} {{ value|placeholder }} {{ value|drupal_escape }} {{ value|safe_join }} {{ value|without }} {{ value|clean_class }} {{ value|clean_id }} {{ value|render }} It's common for a long- standing and complex project to add and remove filters. ! If Drupal removes a filter used by your templates, your site/app will break.
  • 44. Declare filters as deprecated new Twig_SimpleFilter('old_filter', ..., array( 'deprecated' => true, 'alternative' => 'new_filter' ));
  • 45. Declare filters as deprecated new Twig_SimpleFilter('old_filter', ..., array( 'deprecated' => true, 'alternative' => 'new_filter' )); These deprecations notices are not displayed or logged anywhere on Drupal yet. NOTE
  • 46. Avoid missing blocks {% if 'title' is block %} <title>{{ block('title') }}<title> {% endif %}
  • 47. This feature is not available yet. It will be included in the upcoming 1.23 version of Twig. NOTE Avoid missing blocks {% if 'title' is block %} <title>{{ block('title') }}<title> {% endif %}
  • 49. WHY IS THIS IMPORTANT?? Because it will make your templates more readable and it will save you time.
  • 51. <ul> {% for i in 1..3 %} <li>{{ i }}</li> {% endfor %} </ul> <ul> <li>1</li> <li>2</li> <li>3</li> </ul> The "problem" of white spaces Twig template HTML page
  • 52. <ul> {% for i in 1..3 %} <li>{{ i }}</li> {% endfor %} </ul> <ul> <li>1</li> <li>2</li> <li>3</li> </ul> The "problem" of white spaces Twig template HTML page
  • 53. <ul> {% for i in 1..3 %} <li>{{ i }}</li> {% endfor %} </ul> <ul> <li>1</li> <li>2</li> <li>3</li> </ul> The "problem" of white spaces Twig template HTML page
  • 54. <ul> {% for i in 1..3 %} <li>{{ i }}</li> {% endfor %} </ul> <ul> <li>1</li> <li>2</li> <li>3</li> </ul> The "problem" of white spaces Twig template HTML page
  • 55. <ul> {% for i in 1..3 %} <li>{{ i }}</li> {% endfor %} </ul> <ul> <li>1</li> <li>2</li> <li>3</li> </ul> The "problem" of white spaces Twig template HTML page
  • 56. Removing white spaces <ul> {%- for i in 1..3 -%} <li>{{ i }}</li> {%- endfor -%} </ul> <ul> {% spaceless %} {% for i in 1..3 %} <li>{{ i }}</li> {% endfor %} {% endspaceless %} </ul>
  • 57. Please, don't waste your time dealing with white spaces.
  • 58. ! Twig templates should be readable HTML pages should not !
  • 59. ! Twig templates should be readable HTML pages should not this is where you work everyday ! browsers get a minimized and compressed HTML mess
  • 60. Sometimes you should add white spaces…
  • 61. White spaces around HTML attributes <h2{{ title_attributes }}>{{ label }}</h2> core/modules/block/templates/block.html.twig
  • 62. White spaces around HTML attributes <h2{{ title_attributes }}>{{ label }}</h2> core/modules/block/templates/block.html.twig
  • 63. White spaces around HTML attributes <h2{{ title_attributes }}>{{ label }}</h2> core/modules/block/templates/block.html.twig no white space when the attributes are empty <h2 class="..."> ... </h2> <h2> ... </h2>
  • 64. Add white spaces to separate Twig & HTML <h2 {{ title_attributes }}>{{ label }}</h2> ! ! <h2 class="..."> ... </h2> <h2 > ... </h2>
  • 65. Add white spaces to separate Twig & HTML <h2 {{ title_attributes }}>{{ label }}</h2> ! ! <h2 class="..."> ... </h2> <h2 > ... </h2> white space when the attributes are empty
  • 66. Add white spaces to separate Twig & HTML <h2 {{ title_attributes }}>{{ label }}</h2> ! ! <h2 class="..."> ... </h2> <h2 > ... </h2> white space when the attributes are empty IT DOES NOT MATTER Twig template is more readable HTML code with white spaces is still valid
  • 67. Hiding HTML code inside Twig strings <div id="site-name"{{ hide_name ? ' class="hidden"' }}> ! ! ! ! ! <div id="site-name"> <div id="site-name" class="hidden"> core/themes/bartik/templates/maintenance-page.html.twig
  • 68. Hiding HTML code inside Twig strings <div id="site-name"{{ hide_name ? ' class="hidden"' }}> ! ! ! ! ! <div id="site-name"> <div id="site-name" class="hidden"> core/themes/bartik/templates/maintenance-page.html.twig
  • 69. Hiding HTML code inside Twig strings <div id="site-name"{{ hide_name ? ' class="hidden"' }}> ! ! ! ! ! <div id="site-name"> <div id="site-name" class="hidden"> WARNING HTML attributes defined in Twig strings are easy to overlook core/themes/bartik/templates/maintenance-page.html.twig
  • 70. Hiding HTML code inside Twig strings <div id="site-name"{{ hide_name ? ' class="hidden"' }}> ! ! ! ! ! <div id="site-name"> <div id="site-name" class="hidden"> WARNING HTML attributes defined in Twig strings are easy to overlook core/themes/bartik/templates/maintenance-page.html.twig DANGER If you miss this single white space, the page design breaks
  • 71. Don't hide HTML code inside Twig strings <div id="site-name" class="{{ hide_name ? 'hidden' }}"> ! ! ! ! ! <div id="site-name" class=""> <div id="site-name" class="hidden"> HTML & Twig are decoupled A single white space won't break the page
  • 72. Don't hide HTML code inside Twig strings <div id="site-name" class="{{ hide_name ? 'hidden' }}"> ! ! ! ! ! <div id="site-name" class=""> <div id="site-name" class="hidden"> Valid HTML code (tested with the W3C validator) HTML & Twig are decoupled A single white space won't break the page
  • 73. DEBUG
  • 74. WHY IS THIS IMPORTANT?? Because it will save you a lot of time while developing your templates.
  • 75. Configure Twig behavior # sites/default/services.yml parameters: twig.config: debug: true auto_reload: null cache: true
  • 76. Configure Twig behavior # sites/default/services.yml parameters: twig.config: debug: true auto_reload: null cache: true Include debug information in the rendered HTML contents In production server, always set it to false
  • 77. HTML content of a rendered Drupal template <div id="block-bartik-login" class="contextual-region block block-user block-user-login-block" role="form"> <h2>User login</h2> <div data-contextual-id="block:block=bartik_login:langcode=en"></div> <div class="content"> ! <form class="user-login-form" data-drupal-selector="user-login-form" action="/node?destination=/ node" method="post" id="user-login-form" accept-charset="UTF-8"> ! <!-- ... -->
  • 78. HTML content when Twig debug is enabled <!-- THEME DEBUG --> <!-- THEME HOOK: 'block' --> <!-- FILE NAME SUGGESTIONS: * block--bartik-login.html.twig * block--user-login-block.html.twig * block--user.html.twig x block.html.twig --> <!-- BEGIN OUTPUT from 'core/themes/bartik/templates/block.html.twig' --> <div id="block-bartik-login" class="contextual-region block block-user block-user-login-block" role="form"> <h2>User login</h2> <div data-contextual-id="block:block=bartik_login:langcode=en"></div> <div class="content"> ! <!-- THEME DEBUG --> <!-- THEME HOOK: 'form' --> <!-- BEGIN OUTPUT from 'core/themes/classy/templates/form/form.html.twig' --> <form class="user-login-form" data-drupal-selector="user-login-form" action="/node?destination=/
  • 79. How to override the current template <!-- THEME DEBUG --> <!-- THEME HOOK: 'block' --> <!-- FILE NAME SUGGESTIONS: * block--bartik-login.html.twig * block--user-login-block.html.twig * block--user.html.twig x block.html.twig --> <!-- BEGIN OUTPUT from 'core/themes/bartik/templates/block.html.twig' -->
  • 80. How to override the current template <!-- THEME DEBUG --> <!-- THEME HOOK: 'block' --> <!-- FILE NAME SUGGESTIONS: * block--bartik-login.html.twig * block--user-login-block.html.twig * block--user.html.twig x block.html.twig --> <!-- BEGIN OUTPUT from 'core/themes/bartik/templates/block.html.twig' --> Drupal tried to use all these templates…
  • 81. How to override the current template <!-- THEME DEBUG --> <!-- THEME HOOK: 'block' --> <!-- FILE NAME SUGGESTIONS: * block--bartik-login.html.twig * block--user-login-block.html.twig * block--user.html.twig x block.html.twig --> <!-- BEGIN OUTPUT from 'core/themes/bartik/templates/block.html.twig' --> …before deciding to use this template. Drupal tried to use all these templates…
  • 82. Which variables are passed to the template? Built-in templates include comments with the full list of variables passed to the Twig template.
  • 83. Easier way to introspect all variables <pre> {{ dump() }} </pre>
  • 84. Easier way to introspect all variables <pre> {{ dump() }} </pre> It dumps the contents of all the variables defined in the template.
  • 85. It's better to dump just the variables you need <pre> {{ dump(label, title_attributes) }} </pre>
  • 86. It's better to dump just the variables you need <pre> {{ dump(label, title_attributes) }} </pre> It dumps only the given variables
  • 87. CAUTION! Don't forget to rebuild your cache after changing the config files and templates.
  • 91. WHY IS THIS IMPORTANT?? Because it can prevent you a lot of security-related problems.
  • 92. CAUTION! Drupal has replaced the default Twig escaping filter by their own.
  • 93. By default, contents are escaped for HTML Hi {{ content }}! $content = '<strong>John</strong>';
  • 94. By default, contents are escaped for HTML Hi {{ content }}! $content = '<strong>John</strong>'; What you expect… Hi John! What you get… Hi <strong>John </strong>!
  • 95. The "raw" filter prevents the escaping Hi {{ content|raw }}! $content = '<strong>John</strong>';
  • 96. The "raw" filter prevents the escaping Hi {{ content|raw }}! $content = '<strong>John</strong>'; What you expect… Hi John! What you get… Hi John!
  • 97. What if contents are used in URLs or JS? <a href="...?param={{ value }}"></a> ! ! ! <script> var variable = "{{ content }}"; </script>
  • 98. What if contents are used in URLs or JS? <a href="...?param={{ value }}"></a> ! ! ! <script> var variable = "{{ content }}"; </script> WRONG HTML ESCAPING
  • 99. Applying different escaping strategies <a href="...?param={{ value|e('url') }}"></a> ! ! ! <script> var variable = "{{ content|e('js') }}"; </script>
  • 100. Escaping strategies available in Twig {{ content|e('html') }} {{ content|e('js') }} {{ content|e('css') }} {{ content|e('url') }} {{ content|e('html_attr') }}
  • 102. WHY IS THIS IMPORTANT?? Because it allows you to avoid repeating code and it makes your themes easier to maintain.
  • 103. Lots of different ways to reuse templates {% embed %} {% extends %}include() {% set %} {% use %}macro()
  • 104. How often are these alternatives used {% embed %} {% extends %} include( ) {% set %} {% use %} macro( ) Always Sometimes Rarely
  • 105. Lots of different ways to reuse templates {% embed %} {% extends %}include() {% set %} {% use %}macro()
  • 106. Use {% extends %} to share layouts
  • 107. Use {% extends %} to share layouts 1 layout with the common design elements
  • 108. Use {% extends %} to share layouts 1 layout with the common design elements + 4 simple pages which only define their contents
  • 109. layout.twig <!DOCTYPE html> <html> <head> <title> {% block title %}ACME website{% endblock %} </title> </head> <body> <div class="container"> {% block content %}{% endblock %} </div> </body> </html>
  • 110. layout.twig <!DOCTYPE html> <html> <head> <title> {% block title %}ACME website{% endblock %} </title> </head> <body> <div class="container"> {% block content %}{% endblock %} </div> </body> </html>
  • 111. Other templates can reuse this layout {% extends 'layout.twig' %} ! {% block title %}Community{% endblock %} {% block content %} <div> ... </div> {% endblock %}
  • 112. When should you use {% extends %} • To create the layout of your theme. • If your site/app is very complex, create two inheritance levels (base layout and section layouts). layout.twig schedule.twig training.twig extends layout.twig extends schedule.twig
  • 113. Lots of different ways to reuse templates {% embed %} {% extends %}include() {% set %} {% use %}macro()
  • 114. Reusing templates with include( ) ! {{ include('listing.twig') }} ! ! <div> {% for item in items %} <h2>{{ item.title }}</h2> <p>{{ item.content }}</p> {% endfor %} </div> blog/index.twig blog/listing.twig
  • 115. When should you use include( ) • To reuse large fragments of code, such as sidebars, navigation menus, etc.
  • 116. Lots of different ways to reuse templates {% embed %} {% extends %}include() {% set %} {% use %}macro()
  • 117. Repetitive HTML fragments <div class="form-group"> <label for="{{ id }}">{{ label }}</label> <input type="{{ type }}" class="form-control" id="{{ id }}"> </div> Repeating the same HTML code for all the form fields is cumbersome
  • 118. Reusing fragments with macro( ) {% macro form_field(id, label, type="text") %} <div class="form-group"> <label for="{{ id }}">{{ label }}</label> <input type="{{ type }}" class="form-control" id="{{ id }}"> </div> {% endmacro %}
  • 119. Using "macros" inside templates {% import _self as macro %} ! <form> {{ macro.form_field('first_name', 'First Name') }} {{ macro.form_field('last_name', 'Last Name') }} {{ macro.form_field('email', 'Email', 'email') }} ... </form>
  • 120. Using "macros" inside templates {% import _self as macro %} ! <form> {{ macro.form_field('first_name', 'First Name') }} {{ macro.form_field('last_name', 'Last Name') }} {{ macro.form_field('email', 'Email', 'email') }} ... </form> Before using a macro, you must "import" them (they can be defined in a different template)
  • 121. When should you use macro( ) • To reuse short fragments of code, usually in the same template (e.g. listings, grids, forms, etc.) • If your site/app is very complex, store all the macros in a single file and reuse it from any other template.
  • 122. Lots of different ways to reuse templates {% embed %} {% extends %}include() {% set %} {% use %}macro()
  • 123. Grid-based design embed allows to reuse inner page structures (e.g. the 3-column grid)
  • 124. Grid-based design embed allows to reuse inner page structures (e.g. the 3-column grid)
  • 125. You can't use "include" to solve this problem {{ include('common/grid_3.twig') }}
  • 126. You can't use "include" to solve this problem {{ include('common/grid_3.twig') }} you can't change the included contents (you include both the structure and the content)
  • 127. You can't use "extends" to solve this problem {% extends 'common/grid_3.twig' %} ! {% block column1 %} ... {% endblock %} {% block column2 %} ... {% endblock %} {% block column3 %} ... {% endblock %}
  • 128. You can't use "extends" to solve this problem {% extends 'common/grid_3.twig' %} ! {% block column1 %} ... {% endblock %} {% block column2 %} ... {% endblock %} {% block column3 %} ... {% endblock %} you can't make the whole structure of the page (grid 2, grid 3, etc.) because you can't extend from multiple templates at the same time
  • 129. Define a three-column grid template <div class="row"> <div class="col-md-4"> {% block column1 %}{% endblock %} </div> ! <div class="col-md-4"> {% block column2 %}{% endblock %} </div> ! <div class="col-md-4"> {% block column3 %}{% endblock %} </div> </div>
  • 130. Reuse the three-column grid template {% embed 'common/grid_3.twig' %} {% block column1 %} ... contents ... {% endblock %} ! {% block column2 %} ... contents ... {% endblock %} ! {% block column3 %} ... contents ... {% endblock %} {% endembed %}
  • 131. When should you use {% embed %} • To reuse page structures across different templates (e.g. grids)
  • 132. Lots of different ways to reuse templates {% embed %} {% extends %}include() {% set %} {% use %}macro()
  • 133. Reusing fragments with {% set %} {% set navigation %} <a href="...">Previous</a> ... ... <a href="...">Next</a> {% endset %}
  • 134. Reusing fragments with {% set %} {% set navigation %} <a href="...">Previous</a> ... ... <a href="...">Next</a> {% endset %} {{ navigation }} {{ navigation }}
  • 135. When should you use {% set %} • To reuse short fragments of code inside a template (if those fragments are configurable, use a macro). • It's like an internal include() made from inside the template itself.
  • 136. Lots of different ways to reuse templates {% embed %} {% extends %}include() {% set %} {% use %}macro()
  • 137. When should you use {% use %} • This is too advanced and for very specific use cases. • You should probably never use it when creating themes.
  • 139. WHY IS THIS IMPORTANT?? Because Drupal allows to create sites with very advanced needs.
  • 140. Templates created on-the-fly {% set code = 'Hi {{ name }}' %} {% set template = template_from_string(code) %} ! {{ include(template) }}
  • 141. Templates created on-the-fly {% set code = 'Hi {{ name }}' %} {% set template = template_from_string(code) %} ! {{ include(template) }} {% extends template %} {% embed template %} It works here too
  • 142. Templates created on-the-fly {{ include(template_from_string( 'Hi {{ name }}' )) }}
  • 143. Templates created and modified on-the-fly {% set code = 'Hi {{ name }}' %} {% set code = code|replace({ 'Hi': 'Bye' }) %} ! {% set template = template_from_string(code) %} ! {{ include(template) }}
  • 144. Getting the source of any template {{ source('core/modules/block/templates/ block.html.twig') }} It gets the source of the given template without actually rendering it.
  • 145. Imagine a site which allows this customization Section 1 Section 2 Default design
  • 146. Customizable site • Users can provide their own Twig snippets to customize the design and content of some sections. • Problem: even if customization is restricted to a group of controlled users (e.g. "editors") you can't trust those templates.
  • 147. Twig Sandbox • It's used to render "untrusted templates". • It restricts the Twig features that can be used by the template. • Useful for letting users create their own templates and maintain the application safe.
  • 148. Twig Sandbox in practice {% sandbox %} {{ include(section.name ~ '/sidebar.twig') }} {% endsandbox %} ! ! {{ include(section.name ~ '/sidebar.twig', sandboxed = true) }}
  • 149. Twig Sandbox in practice $policy = new Twig_Sandbox_SecurityPolicy( $tags, $filters, $methods, $properties, $functions ); ! $sandbox = new Twig_Extension_Sandbox($policy); $twig->addExtension($sandbox); Policy is defined as a white-list of allowed tags, filters, etc.
  • 150. Twig Sandbox policy sample $properties = array( 'label', 'configuration' => array('label', 'module'), 'block' => array('module'), 'attributes', ); ! $policy = new Twig_Sandbox_SecurityPolicy( $tags, $filters, $methods, $properties, $functions );
  • 151. DATES
  • 152. WHY IS THIS IMPORTANT?? Because dealing with dates is not easy and Twig can perform a lot of operations on dates.
  • 153. Timezones support {{ 'now'|date(timezone='Asia/Tokyo') }} ! {{ 'now'|date(timezone=user.timezone) }}
  • 154. Comparing dates {% if event.startsAt > date('now') %} Buy tickets {% endif %}
  • 155. Comparing dates {% if event.startsAt > date('now') %} Buy tickets {% endif %} NOTE This is the date( ) function, not the date filter
  • 156. Modifying dates semantically Early Bird ends at {{ event.startsAt|date_modify('-15 days')|date }} ! Confirm your sign up before {{ user.createdAt|date_modify('+48 hours')|date }}
  • 158. These are some of the features that put Twig years ahead of PHP
  • 159. Useful filters for collections {{ user.friends|first }} {{ event.sessions|last }}
  • 160. Useful tests for strings {% if url starts with 'https://' %} {% endif %} ! {% if file_path ends with '.pdf' %} {% endif %} ! {% if phone matches '/^[d.]+$/' %} {% endif %}
  • 161. REJECTED BY PHP Useful tests for strings {% if url starts with 'https://' %} {% endif %} ! {% if file_path ends with '.pdf' %} {% endif %} ! {% if phone matches '/^[d.]+$/' %} {% endif %}
  • 162. The "in" operator {% if password in username %} BAD PASSWORD {% endif %} ! {% if method in ['GET', 'POST'] %} ... {% endif %}
  • 163. The "in" operator {% if password in username %} BAD PASSWORD {% endif %} ! {% if method in ['GET', 'POST'] %} ... {% endif %} REJECTED BY PHP
  • 165. Named parameters {{ content|convert_encoding('UTF-8', 'iso-2022-jp') }} which is the original charset and which one the target charset?
  • 166. Named parameters {{ content|convert_encoding('UTF-8', 'iso-2022-jp') }} which is the original charset and which one the target charset? {{ content|convert_encoding( from = 'UTF-8', to = 'iso-2022-jp' ) }}
  • 167. Named parameters {{ content|convert_encoding('UTF-8', 'iso-2022-jp') }} which is the original charset and which one the target charset? {{ content|convert_encoding( from = 'UTF-8', to = 'iso-2022-jp' ) }} {{ content|convert_encoding( to = 'UTF-8', from = 'iso-2022-jp' ) }}
  • 168. Named parameters {{ content|convert_encoding('UTF-8', 'iso-2022-jp') }} PROPOSED FOR PHP which is the original charset and which one the target charset? {{ content|convert_encoding( from = 'UTF-8', to = 'iso-2022-jp' ) }} {{ content|convert_encoding( to = 'UTF-8', from = 'iso-2022-jp' ) }}
  • 169. Named parameters {{ include('template.html', {}, true, true) }} ! ! ! {{ include('template.html', ignore_missing = true) }} template variables with_context ignore_missing
  • 170. It's common to do things in batches 1 Image gallery 2 3 4 5 6
  • 171. The HTML of the image gallery <div class="row"> <div class="image"> ... </div> <div class="image"> ... </div> <div class="image"> ... </div> </div> ! <div class="row"> <div class="image"> ... </div> <div class="image"> ... </div> <div class="image"> ... </div> </div>
  • 172. The template without the "batch" filter {% for i, image in images %} {% if i is divisible by(3) %} <div class="row"> {% endif %} ! <div class="image"> <img src="" alt="" > <p>...</p> </div> ! {% if i is divisible by(3) %} </div> {% endif %} {% endfor %}
  • 173. The template without the "batch" filter {% for i, image in images %} {% if i is divisible by(3) %} <div class="row"> {% endif %} ! <div class="image"> <img src="" alt="" > <p>...</p> </div> ! {% if i is divisible by(3) %} </div> {% endif %} {% endfor %} UGLY CODE
  • 174. The template with the "batch" filter {% for row in images|batch(3) %} <div class="row"> ! {% for image in row %} <div class="image"> <img src="" alt="" > <p>...</p> </div> {% endfor %} ! </div> {% endfor %}
  • 175. The template with the "batch" filter {% for row in images|batch(3) %} <div class="row"> ! {% for image in row %} <div class="image"> <img src="" alt="" > <p>...</p> </div> {% endfor %} ! </div> {% endfor %}
  • 176. Short ternary operator $result = $condition ? 'is true';
  • 177. Short ternary operator $result = $condition ? 'is true'; ERROR Parse error: syntax error, unexpected ';' on line 1
  • 178. Short ternary operator $result = $condition ? 'is true'; ERROR Parse error: syntax error, unexpected ';' on line 1 {{ condition ? 'is true' }}
  • 179. Short ternary operator $result = $condition ? 'is true'; ERROR Parse error: syntax error, unexpected ';' on line 1 OK This works perfectly on Twig {{ condition ? 'is true' }}
  • 180. Short ternary operator <li class="{{ condition ? 'selected' }}"> ... </li> ! <li class="{{ condition ? 'selected' : '' }}"> ... </li>
  • 181. Short ternary operator <li class="{{ condition ? 'selected' }}"> ... </li> ! <li class="{{ condition ? 'selected' : '' }}"> ... </li> always use this
  • 182. Short slice syntax ! ! ! {{ user.friends[0:3] }} {{ user.friends[:-3] }} It combines array_slice, mb_substr and substr PHP functions. get first three friends get last three friends
  • 183. Short slice syntax {{ '0123456789'[0:] }} {# 0123456789 #} {{ '0123456789'[1:] }} {# 123456789 #} {{ '0123456789'[20:] }} {# (empty) #} {{ '0123456789'[-5:] }} {# 56789 #} {{ '0123456789'[-1:] }} {# 9 #} {{ '0123456789'[1:5] }} {# 12345 #} {{ '0123456789'[1:-5] }} {# 1234 #} OUTPUT
  • 184. The "loop" magic variable Everyone needs an $i variable inside the for loop. So Twig provides you this and other useful variables.
  • 185. The "loop" variable exists only inside the "for" {% for ... in collection %} {{ loop.index }} {{ loop.index0 }} {{ loop.first }} {{ loop.last }} {{ loop.length }} {% endfor %}
  • 186. The "loop" variable exists only inside the "for" {% for ... in collection %} {{ loop.index }} {{ loop.index0 }} {{ loop.first }} {{ loop.last }} {{ loop.length }} {% endfor %} 1, 2, 3, 4, 5, ... 0, 1, 2, 3, 4, ... true, false, false, ... ..., false, false, true 5
  • 187. {{ product.photo|image(400, 150, 0.9) }} The problem with filter arguments
  • 188. {{ product.photo|image(400, 150, 0.9) }} The problem with filter arguments What if I need to define more arguments?
  • 189. {{ product.photo|image(400, 150, 0.9) }} {{ product.photo|image( width = 400, height = 150, opacity = 0.9 ) }} The problem with filter arguments What if I need to define more arguments?
  • 190. {{ product.photo|image(400, 150, 0.9) }} {{ product.photo|image( width = 400, height = 150, opacity = 0.9 ) }} The problem with filter arguments What if I need to define more arguments? this is a valid solution for Twig, but the underlying PHP code is still very complex
  • 191. Defining a filter with lots or arguments $filter = new Twig_SimpleFilter('image', function ( $path, $width, $height, $opacity ) { $path = ... $width = ... $height = ... $opacity = ... });
  • 192. $filter = new Twig_SimpleFilter('image', function ( $path, $options = array() ) { $path = ... $width = $options['width']; $height = $options['height']; $opacity = $options['opacity']; }, array('is_variadic' => true)); Defining a variadic filter
  • 193. $filter = new Twig_SimpleFilter('image', function ( $path, $options = array() ) { $path = ... $width = $options['width']; $height = $options['height']; $opacity = $options['opacity']; }, array('is_variadic' => true)); Defining a variadic filter a single variadic parameter holds any number of passed parameters (unlimited)
  • 194. $filter = new Twig_SimpleFilter('image', function ( $path, $options = array() ) { $path = ... $width = $options['width']; $height = $options['height']; $opacity = $options['opacity']; }, array('is_variadic' => true)); ACCEPTED BY PHP Defining a variadic filter a single variadic parameter holds any number of passed parameters (unlimited)
  • 196. «Using Twig templates is the best decision Drupal ever made»
  • 197. Drupal 8 templates are safe, concise, modern and consistent. Twig
  • 198. Drupal 8 templates are safe, concise, modern and consistent.
  • 201. References • Official Twig documentation
 twig.sensiolabs.org/documentation
 • Twig in Drupal 8
 drupal.org/theme-guide/8/twig
  • 203. Contact info • javier.eguiluz@sensiolabs.com • github.com/javiereguiluz • linkedin.com/in/javiereguiluz ! ! !