Twig Brief, Tips&Tricks

34
TWIG Tips & Tricks

Transcript of Twig Brief, Tips&Tricks

TWIGTips & Tricks

STRUCTURE AND

INTERNAL REPRESENTATION

Twig's three tagsTwig parses just three simple tags:

{# comment tag - aren't rendered and they are also multi-line#} – do nothing!

{{ 'print tag' }} – say something!

{% set this = 'block tag' %} - do something!

The LexerThe lexer tokenizes a template source code into a token stream. The default

lexer recognizes 13 different token types.

Here is the output for the Hello {{ name }} template:

TEXT_TYPE(Hello )VAR_START_TYPE()NAME_TYPE(name)VAR_END_TYPE()EOF_TYPE()

The ParserThe parser converts the token stream into an AST (Abstract Syntax Tree), or

a node tree. The core extension defines the basic nodes like: for, if, ... and the expression nodes.

Here is the output for the Hello {{ name }} template:

Twig_Node_Module( Twig_Node_Text(Hello ) Twig_Node_Print( Twig_Node_Expression_Name(name) ))

Templates’ sourcesapp/cache/prod/templates.php :

<?php return array ('::base.html.twig' => '<project_path>/app/Resources/views/base.html.twig','::header.html.twig' => '<project_path>/app/Resources/views/header.html.twig','::footer.html.twig' => '<project_path>/app/Resources/views/footer.html.twig','CrfMainBundle:Homepage:homepage.html.twig' => '<project_path>/src/Crf/MainBundle/Resources/views/Homepage/homepage.html.twig',

…);

The CompilerThe last step is done by the compiler. It takes a node tree as an input and

generates PHP code usable for runtime execution of the template.

The generated template for a Hello {{ name }} template reads as follows:

/* Hello {{ name }} */class __TwigTemplate_1121b6f109fe93ebe8c6e22e3712bceb extends Twig_Template{ protected function doDisplay(array $context, array $blocks = array()) { // line 1 echo "Hello "; echo twig_escape_filter($this->env, $this->getContext($context, "name"), "html", null, true); }

// some more code}

FUNCTIONALITIES AND

USAGE

FOR Loops{% for user in users %}

{{user.name}}{% else %}

{{ ‘No users’ }}{% endfor %}

{% for i in 0..10 %}{% for l in 'a'..'z' %}{% for l in 'a'|upper..'z'|upper %}{% for i in 0|range(10, 2) %}

{% for blog in blogs %} <div class="link {{ cycle(['even', 'odd'], loop.index0) }}">

{{ blog.description }}</div> {% endfor %}

IF TagMultiple branches:

{% if kenny.sick %} Kenny is sick.{% elseif kenny.dead %} You killed Kenny! You bastard!!!{% else %} Kenny looks okay --- so far{% endif %}

Ternary operator:

{{ human.alive ? ‘It’s alive’ : ‘Wasted’ }}

- define a macro in a separate twig file:

- include your reusable macro where you want:

MACROS - a reusable and configurable snippet of HTML

XSS protection - escaping

SpacelessUse the spaceless tag to remove whitespace between HTML tags, not whitespace within HTML tags or whitespace in plain text:

{% spaceless %} <div> <strong>foo bar</strong> </div>{% endspaceless %}{# output will be <div><strong>foo bar</strong></div> #}

{% set value = 'no spaces' %}<li> {{- value }} </li>{# outputs '<li>no spaces </li>' #}

VerbatimThe verbatim tag marks sections as being raw text that should not be parsed. For example to put Twig syntax as example into a template you can use this snippet:

{% verbatim %} <ul> {% for item in seq %} <li>{{ item }}</li> {% endfor %} </ul>{% endverbatim %}

You can also use this tag to avoid the conflict with the default angular.js syntax, if you do not want to change it.

The i18n extensionTo use it, first, install the Extensions library.You need to register this extension before using the trans block, then configure the gettext extension:

// Set language to Frenchputenv('LC_ALL=fr_FR');setlocale(LC_ALL, 'fr_FR');// Specify the location of the translation tablesbindtextdomain('myAppPhp', 'includes/locale');bind_textdomain_codeset('myAppPhp', 'UTF-8');// Choose domaintextdomain('myAppPhp');

{% trans "Hello World!" %}

{% trans string_variable %}

{% trans %} Hello {{ name }}{% endtrans %}

EXTENDING AND

CUSTOMIZING

Setting your own custom syntaxYou may want to use simultaneously the default syntax of angular( {{ }} ) with twig - what to do?Change the twig default syntax to your preferred one!

Creating a TWIG extensionTwig is very customizable, and allows you to create custom tools, like tags,

filters, operators, functions by extending the core(lib\twig\Extension\Core.php) .The principle of creating an extension is the same for any element you

wish to customize: you create a class which extends the \Twig_Extension abstract class, then overwrite the desired function, and inject your service or create a custom function which you intend to use in the templates.

use it in your templates:

{{ entityHelper.attributeByStore(promo, attribute) }}

Sandbox• It’s a regular Twig extension, {% sandbox %}• Disabled by default.• It allows to restrict the functions, filters, tags and object properties used in the templates.• It’s based on security policies.

$loader = new Twig_Loader_Filesystem('...');$twig = new Twig_Environment($loader, array());$properties = array(‘User’ => array('name', 'address'));$policy = new Twig_Sandbox_SecurityPolicy(

array(), array(), array(), $properties, array());$sandbox = new Twig_Extension_Sandbox(

$policy, true // all templates are sandboxed);$twig->addExtension($sandbox);

The template now displays an error:

{% sandbox %} {% include 'user.html' %}{% endsandbox %}

{{ user.name }} - ok{{ user.address }} - ok{{ user.age }} - is not accessibleWhoops, looks like something went wrong.User: {{ user.age }}Calling "age" property on a "User" object is not allowed …

Security policy arguments:$policy = new Twig_Sandbox_SecurityPolicy(

$tags,$filters,$methods,$properties,$functions

);

Allow just 3 filters:$policy = new Twig_Sandbox_SecurityPolicy(

$tags,array('escape', 'upper', 'lower'),$methods,$properties,$functions

);

{{ include }} vs {% include %}1) If you want to store contents of a file in a variable if you want to repeat it twice:

{% set content = include('test.twig') %}Instead of:

{% set content %}

{% include 'test.twig' %}

{% endset %}

2) If you want to add filters:

{{ include('alert.twig') | upper }}Its tag equivalent:

{% set temp %} {% include 'alert.twig' %}

{% endset %} {{ temp | upper }}

Also, according to the documentation, it looks recommended to use {{ include() }} to fit with best practices.

Conditional layouts{% extends request.ajax ? "base_ajax.html" : "base.html" %}

{% block content %} This is the content to be displayed.{% endblock %}

Dynamic inclusion of a template:

{% include var|default('index') ~ '_foo.html' %}

Accessing an object attribute{{ user.name }}

name can be:* an item on an array* property on an object* getName()

{{ user[‘name’] }}

or you can force it to *just* fetch “name” as an array item

Convert format and format date

Defensive design

Use a default value when possible:{{ variable|default("value") }}

Ignore missing templates:{% include 'section_' ~ slug ~ '.twig' ignore missing %}

Define fallback templates{% extends ['layout_' ~ locale ~ '.html.twig', 'layout.html.twig'] %}

Render a Template without a custom Controlleracme_privacy:

path: /privacy

defaults:

_controller: FrameworkBundle:Template:template

template: static/privacy.html.twig

maxAge: 86400

sharedAge: 86400

{{ render(url('acme_privacy')) }}

Thank you very much for your attendance!

Useful links:http://twig.sensiolabs.org/

http://symfony.com/doc/current/components/templating/index.html

http://symfony.com/doc/current/cookbook/templating/index.html

http://fabien.potencier.org/article/34/templating-engines-in-php

http://www.slideshare.net/fabpot/twig-the-flexible-fast-and-securetemplate-language-for-php

http://www.slideshare.net/cesaredamico/webtech-twig

http://www.slideshare.net/weaverryan/being-dangerous-with-twig

http://www.slideshare.net/javier.eguiluz/twig-tips-and-tricks