Slide 1

Slide 1 text

Twig does not make templating your enemy!

Slide 2

Slide 2 text

Hugo Hamon @hhamon Head of training at SensioLabs PHP fan for 10 years Travel addict Speaker at many conferences Book author

Slide 3

Slide 3 text

How many of you are… … web designers? … web developers?

Slide 4

Slide 4 text

So you really think PHP is a good template engine?

Slide 5

Slide 5 text

You’re totally wrong! J

Slide 6

Slide 6 text

Contextual content Manual escaping No isolation No separation of concerns

Slide 7

Slide 7 text

Are you kidding me?

Slide 8

Slide 8 text

Why and when using a template engine?

Slide 9

Slide 9 text

What about existing template engines?

Slide 10

Slide 10 text

Twig

Slide 11

Slide 11 text

1. Installation & bootstrap 2. Twig for web designers 3. Twig for developers 4. Frameworks & CMS

Slide 12

Slide 12 text

1. Installation & bootstrap

Slide 13

Slide 13 text

Packages Installation https://github.com/fabpot/twig twig/twig

Slide 14

Slide 14 text

Extension Installation $ cd ext/twig $ phpize $ ./configure $ make $ make install extension = twig.so

Slide 15

Slide 15 text

Bootstrapping require __DIR__.'/vendor/autoload.php'; $loader = new Twig_Loader_Filesystem('/path/to/views'); $twig = new Twig_Environment($loader, array( 'cache' => '/path/to/cache', )); echo $twig->render('hello.twig', array( 'name' => 'Hugo' ));

Slide 16

Slide 16 text

2. Twig for web designers

Slide 17

Slide 17 text

Concise templating syntax

Slide 18

Slide 18 text

Concise Syntax {# ... comment something ... #} {% ... do something ... %} {{ ... display something ... }}

Slide 19

Slide 19 text

PHP compilation and cache

Slide 20

Slide 20 text

PHP Compilation and Cache {# just say hello #} Hello {{ name }}!

Slide 21

Slide 21 text

PHP Compilation and Cache class __TwigTemplate_df6deba4655fee022981430 extends Twig_Template { protected function doDisplay(array $context, array $blocks = array()) { // line 1 echo "Hello "; echo twig_escape_filter($this->env, (isset($context["name"]) ? $context["name"] : null), "html", null, true); echo "!"; } // ... } Escaping is enabled

Slide 22

Slide 22 text

Debugging

Slide 23

Slide 23 text

Accurate Debugging Hello {{ rand(['John', 'Tom', 'Paul']) }}! Twig_Error_Syntax: The function "rand" does not exist. Did you mean "random" in "hello.twig" at line 3

Slide 24

Slide 24 text

Dumping a Variable {% set names = ['John', 'Tom', 'Paul'] %} {{ dump(names) }}

Slide 25

Slide 25 text

Strict Variables Enabled Hello {{ nam }}! Twig_Error_Runtime: Variable "nam" does not exist in "hello.twig" at line 1

Slide 26

Slide 26 text

Output escaping

Slide 27

Slide 27 text

Automatic Output Escaping Hello {{ name }}! The variable is automatically escaped if it contains a string

Slide 28

Slide 28 text

Escaping Strategies {{ name|raw }} {{ name|escape }} {{ name|e }} {{ name|e('html') }} {{ name|e('html_attr') }} {{ name|e('js') }} {{ name|e('css') }} {{ name|e('url') }}

Slide 29

Slide 29 text

Output Escaping {% autoescape %} Everything will be automatically escaped in this block using the HTML strategy {% endautoescape %} {% autoescape 'js' %} Everything will be automatically escaped in this block using the js escaping strategy {% endautoescape %} {% autoescape false %} Everything will be outputted as is in this block {% endautoescape %}x

Slide 30

Slide 30 text

Variables

Slide 31

Slide 31 text

Variables Abstraction {{ article.title }} The article can be an array or an object. The title can be a key of the array, a public property, a regular method or a getter method.

Slide 32

Slide 32 text

Variables Abstraction echo $article['title']; echo $article->title; echo $article->title(); echo $article->getTitle(); echo $article->isTitle();

Slide 33

Slide 33 text

Loops & Conditions

Slide 34

Slide 34 text

Making Decisions {% if product.stock > 10 %} Available {% elseif product.stock > 0 %} Only {{ product.stock }} left! {% else %} Sold-out! {% endif %}

Slide 35

Slide 35 text

Iterating Over a Collection
{% for post in posts if post.active %}

{{ post.title }}

{{ post.body }} {% else %} No published posts yet. {% endfor %}

Slide 36

Slide 36 text

Get the Loop Context Variable Description loop.index The current iteration of the loop. (1 indexed) loop.index0 The current iteration of the loop. (0 indexed) loop.revindex The number of iterations from the end of the loop (1 indexed) loop.revindex0 The number of iterations from the end of the loop (0 indexed) loop.first True if rst iteration loop.last True if last iteration loop.length The number of items in the sequence loop.parent The parent context

Slide 37

Slide 37 text

Operators

Slide 38

Slide 38 text

Operators o  Math: +, -, /, *, **, % o  Logical: or, and, xor o  Concatenation: ~ o  Comparison: <, >, <=, >=, == o  Containment: in, not in

Slide 39

Slide 39 text

Functions

Slide 40

Slide 40 text

Generating Contents Hello {{ random(['John', 'Tom', 'Paul']) }}! {% for i in range(0,10) %} {{ cycle(['odd', 'even'], i) }}
{% endfor %}

Slide 41

Slide 41 text

Built-in Functions o  attribute o  block o  constant o  cycle o  date o  parent o  random o  range

Slide 42

Slide 42 text

Filters

Slide 43

Slide 43 text

Formatting Contents {{ post.publishedAt|date('d/m/Y') }} {{ post.title|lower }} {{ post.title|upper }} {{ post.title|capitalize }} {{ post.title|title }} {{ post.tags|sort|join(', ') }} {{ post.author|default('Anonymous') }}

Slide 44

Slide 44 text

Built-in Filters o  abs o  capitalize o  convert_encoding o  date o  date_modify o  default o  escape o  format o  join o  json_encode o  keys o  length o  lower o  merge o  nl2br o  number_format o  raw o  replace o  reverse o  slice o  sort o  striptags o  title o  trim o  upper o  url_encode

Slide 45

Slide 45 text

Whitespace Control

Slide 46

Slide 46 text

Whitespace Control {% spaceless %}

Hello {{ name }}!

{% endspaceless %}

Hello Hugo!

Slide 47

Slide 47 text

Whitespace Control

Hello {{- name }} !

Hello Hugo !

Value is trimmed on the left.

Slide 48

Slide 48 text

Template inclusion

Slide 49

Slide 49 text

Template Inclusion {% include "list.twig" with { "section": "blog", "posts": articles } only %} The included template is rendered with its own context. Isolation

Slide 50

Slide 50 text

Template inheritance

Slide 51

Slide 51 text

layout.twig {% block body %} {% endblock body %} {% block breadcrumb %} ... {% endblock %} blog.twig {% extends "layout.twig" %} {% block breadcrumb %} {{ parent() }} - Blog {% endblock breadcrumb %} {% block body %}

Latest posts

{% include "posts.twig" %} {% endblock body %}

Slide 52

Slide 52 text

{% extends "layout.twig" %} {% block breadcrumb %} {{ parent() }} - Blog {% endblock breadcrumb %} {% block body %}

Latest posts

{% include "posts.twig" %} {% endblock body %} Template Inheritance Extend the parent template. Reuse the parent block default value. Fill the parent body block.

Slide 53

Slide 53 text

No content

Slide 54

Slide 54 text

Macros

Slide 55

Slide 55 text

Defining Macros {% macro input(name, value, type, size) %} {% endmacro %} Default argument values are defined with the default filter

Slide 56

Slide 56 text

Using Macros {% import "forms.html" as forms %}

{{ forms.input('username') }}

Macros are imported under a specific namespace The macro is called with the prefixed namespace

Slide 57

Slide 57 text

Sandboxed environment

Slide 58

Slide 58 text

Whitelist Filtering $tags = array('if'); $functions = array('range'); $filters = array('upper'); $methods = array( 'Article' => array('getTitle', 'getBody'), 'Tag' => array('getName'), ); $properties = array( 'Article' => array('title', 'body'), 'Tag' => array('name'), );

Slide 59

Slide 59 text

Enabling Sandbox Mode $policy = new Twig_Sandbox_SecurityPolicy( $tags, $filters, $methods, $properties, $functions ); $sandbox = new Twig_Extension_Sandbox($policy); $twig = new Twig_Environment(); $twig->addExtension($sandbox);

Slide 60

Slide 60 text

Using the Sandbox Mode {% sandbox %} {% include 'users.html' %} {% endsandbox %}

Slide 61

Slide 61 text

Enabling Sandbox Mode $sandbox = new Twig_Extension_Sandbox($policy, true); Sandbox mode is automatically enabled for all template

Slide 62

Slide 62 text

Enabling Sandbox Mode {% block foo 'bar' %} {% include 'users.html' %} Twig_Sandbox_SecurityError: Tag "block" is not allowed in "hello.twig" at line 2

Slide 63

Slide 63 text

3. Twig for developers

Slide 64

Slide 64 text

I want to customize Twig!

Slide 65

Slide 65 text

Internal Architecture Lexer Parser Compiler Extension Extension Extensions Twig_Environment

Slide 66

Slide 66 text

The Twig Lexer $template = <<tokenize($template);

Slide 67

Slide 67 text

The Twig Parser $ast = $twig->parse($stream); Twig_Node_Module( Twig_Node_Text(Hello ) Twig_Node_Print( Twig_Node_Expression_Name(name) ) Twig_Node_Text(!) )

Slide 68

Slide 68 text

The Twig Compiler $php = $twig->compile($ast); class __TwigTemplate_1121b6f109fe93ebe8c6e22e3712b 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"), "ndex", null, true); echo "!"; } // some more code }

Slide 69

Slide 69 text

Configuring Twig $twig = new Twig_Environment(array( 'strict_variables' => true, 'debug' => true, 'cache' => '/path/to/cache', 'base_template_class' => 'MyTemplate', 'autoescape' => 'js', 'optimizations' => -1, ));

Slide 70

Slide 70 text

Customizing Twig T ags $twig = new Twig_Environment(); $lexer = new Twig_Lexer($twig, array( 'tag_comment' => array('{*', '*}'), 'tag_block' => array('{', '}'), 'tag_variable' => array('{$', '}'), )); $twig->setLexer($lexer); Smarty tags

Slide 71

Slide 71 text

Twig extensions

Slide 72

Slide 72 text

Extending the Twig Gramar o  Global variables o  Global functions o  Filters o  Tests o  Operators o  T ags

Slide 73

Slide 73 text

Built-in Extensions Exension name Description Core Provides the core features Debug Provides debugging tools like the dump() function Escaper Provides escaping tools Optimizer Provides optimization tools Sandbox Provides the sandboxed environment capabilities

Slide 74

Slide 74 text

The Twig Extension Class abstract class Twig_Extension implements Twig_ExtensionInterface { public function initRuntime(Twig_Environment $environment); public function getTokenParsers(); public function getNodeVisitors(); public function getFilters(); public function getTests(); public function getFunctions(); public function getOperators(); public function getGlobals(); }

Slide 75

Slide 75 text

Creating a Twig Extension class GravatarExtension extends \Twig_Extension { public function getName() { return 'gravatar'; } } The abstract getName() method must be implemented.

Slide 76

Slide 76 text

Registering the Extension $extension = new GravatarExtension(); $twig = new Twig_Environment(); $twig->addExtension($extension); Easy uh?!

Slide 77

Slide 77 text

Adding a new Global Function class GravatarExtension extends \Twig_Extension { public function getFunctions() { return array( 'gravatar' => new \Twig_Function_Method($this, 'getGravatar'), ); } public function getGravatar($email, $size = '80', $rating = 'g') { $url = 'http://www.gravatar.com/avatar/%s?size=%u&rating=%s'; $hash = md5(strtolower(trim($email))); return sprintf($url, $hash, (int) $size, $rating); } }

Slide 78

Slide 78 text

Using the Global Function {% set uri = gravatar("[email protected]") %} hhamon Twig now knows this function.

Slide 79

Slide 79 text

4. Frameworks & CMS

Slide 80

Slide 80 text

I want to use Twig with my favorite framework or CMS!

Slide 81

Slide 81 text

Symfony 1.4 sfTwigPlugin http://www.symfony-project.org/plugins/sfTwigPlugin

Slide 82

Slide 82 text

Symfony2 Built-in Forms themes Render tag Trans tag Routing functions Yaml filters …

Slide 83

Slide 83 text

Zend Framework 1 Ano_ZFTwig Automatic escaping Layout inheritance Javascripts helpers Stylesheets helpers Routing helpers https://github.com/benjamindulau/Ano_ZFTwig

Slide 84

Slide 84 text

Zend Framework 2 Zfc_Twig Automatic escaping Layout inheritance Action rendering Forms helpers Events triggering https://github.com/ZF-Commons/ZfcTwig

Slide 85

Slide 85 text

Drupal 7 Drupal themes Switch/Case tag I18n capabilities Extra filters Extra functions http://drupal.org/sandbox/ReneB/1075966

Slide 86

Slide 86 text

WordPress o  http://wordpress.org/extend/plugins/ap-twig-bridge/ o  http://inchoo.net/wordpress/twig-wordpress-part2/ o  https://github.com/cordoval/Twig-for-WordPress o  https://github.com/maxcal/Twigpress

Slide 87

Slide 87 text

Questions ?

Slide 88

Slide 88 text

Join us in Berlin! Symfony Live November 22nd – 23rd

Slide 89

Slide 89 text

Community Feedbacks

Slide 90

Slide 90 text

Thank You!