Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Twig doesn’t make templating your enemy!

Hugo Hamon
October 06, 2012

Twig doesn’t make templating your enemy!

Twig is a modern templating engine, which takes inspiration on the Smarty PHP project and Django Jinja templates in Python. Twig comes with an easy-to-use syntax and large modern features set for building web application. This talk will first introduce Twig and most of its native templating API including output escaping, data formatting, template inheritance, caching… In a second part, you will learn how you can easily extend Twig with third party extensions or by creating your own extensions. Finally, you will discover how you can integrate Twig with major PHP frameworks such as Symfony2, Zend Framework and even WordPress.

Hugo Hamon

October 06, 2012
Tweet

More Decks by Hugo Hamon

Other Decks in Technology

Transcript

  1. Twig does not make
    templating your enemy!

    View Slide

  2. Hugo Hamon
    @hhamon


    Head of training at SensioLabs

    PHP fan for 10 years

    Travel addict

    Speaker at many conferences

    Book author

    View Slide

  3. How many of you are…

    … web designers?
    … web developers?

    View Slide

  4. So you really think
    PHP is a good template
    engine?

    View Slide

  5. You’re totally wrong!
    J

    View Slide












  6. Contextual content
    Manual escaping
    No isolation
    No separation of
    concerns

    View Slide

  7. Are you kidding me?

    View Slide

  8. Why and when using
    a template engine?

    View Slide

  9. What about existing
    template engines?

    View Slide

  10. Twig

    View Slide

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

    View Slide

  12. 1. Installation & bootstrap

    View Slide

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

    View Slide

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

    View Slide

  15. 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'
    ));

    View Slide

  16. 2. Twig for web designers

    View Slide

  17. Concise templating
    syntax

    View Slide

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

    View Slide

  19. PHP compilation
    and cache

    View Slide

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

    View Slide

  21. 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

    View Slide

  22. Debugging

    View Slide

  23. 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

    View Slide

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

    View Slide

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

    View Slide

  26. Output escaping

    View Slide

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

    View Slide

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

    View Slide

  29. 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

    View Slide

  30. Variables

    View Slide

  31. 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.

    View Slide

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

    View Slide

  33. Loops & Conditions

    View Slide

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

    View Slide

  35. Iterating Over a Collection

    {% for post in posts if post.active %}
    {{ post.title }}
    {{ post.body }}
    {% else %}
    No published posts yet.
    {% endfor %}

    View Slide

  36. 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

    View Slide

  37. Operators

    View Slide

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

    View Slide

  39. Functions

    View Slide

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

    {% endfor %}

    View Slide

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

    View Slide

  42. Filters

    View Slide

  43. 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') }}

    View Slide

  44. 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

    View Slide

  45. Whitespace Control

    View Slide

  46. Whitespace Control
    {% spaceless %}

    Hello {{ name }}!

    {% endspaceless %}
    Hello Hugo!

    View Slide

  47. Whitespace Control

    Hello {{- name }} !

    Hello Hugo !
    Value is trimmed on the left.

    View Slide

  48. Template inclusion

    View Slide

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

    View Slide

  50. Template inheritance

    View Slide

  51. 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 %}

    View Slide

  52. {% 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.

    View Slide

  53. View Slide

  54. Macros

    View Slide

  55. Defining Macros
    {% macro input(name, value, type, size) %}
    name="{{ name }}"
    value="{{ value|e }}"
    size="{{ size|default(20) }}" />
    {% endmacro %}
    Default argument values are
    defined with the default filter

    View Slide

  56. 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

    View Slide

  57. Sandboxed
    environment

    View Slide

  58. 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'),
    );

    View Slide

  59. 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);

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  63. 3. Twig for developers

    View Slide

  64. I want to customize
    Twig!

    View Slide

  65. Internal Architecture
    Lexer
    Parser
    Compiler
    Extension
    Extension
    Extensions
    Twig_Environment

    View Slide

  66. The Twig Lexer
    $template = <<Hello {{ name }}!
    EOT;
    $twig = new Twig_Environment();
    $stream = $twig->tokenize($template);

    View Slide

  67. 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(!)
    )

    View Slide

  68. 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
    }

    View Slide

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

    View Slide

  70. 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

    View Slide

  71. Twig extensions

    View Slide

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

    View Slide

  73. 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

    View Slide

  74. 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();
    }

    View Slide

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

    View Slide

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

    View Slide

  77. 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);
    }
    }

    View Slide

  78. Using the Global Function
    {% set uri = gravatar("[email protected]") %}

    Twig now knows this
    function.

    View Slide

  79. 4. Frameworks & CMS

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  85. Drupal 7
    Drupal themes
    Switch/Case tag
    I18n capabilities
    Extra filters
    Extra functions

    http://drupal.org/sandbox/ReneB/1075966

    View Slide

  86. 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

    View Slide

  87. Questions
    ?

    View Slide

  88. Join us in Berlin!

    Symfony Live
    November 22nd – 23rd

    View Slide

  89. Community Feedbacks

    View Slide

  90. Thank You!

    View Slide