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

Twig doesn’t make templating your enemy!

E2ed7c278c8c49bb3e7fe0b7de039997?s=47 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.

E2ed7c278c8c49bb3e7fe0b7de039997?s=128

Hugo Hamon

October 06, 2012
Tweet

Transcript

  1. Twig does not make templating your enemy!

  2. Hugo Hamon @hhamon Head of training at SensioLabs PHP fan

    for 10 years Travel addict Speaker at many conferences Book author
  3. How many of you are… … web designers? … web

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

  5. You’re totally wrong! J

  6. <?php include 'header.php' ?> <?php include 'footer.php' ?> <div class="posts">

    <?php foreach ($posts as $post) : ?> <h2> <?php echo htmlspecialchars($post['title']) ?> </h2> <?php include 'post.php' ?> <?php echo substr($post['body'], 255).'...' ?> <?php endforeach ?> </div> Contextual content Manual escaping No isolation No separation of concerns
  7. Are you kidding me?

  8. Why and when using a template engine?

  9. What about existing template engines?

  10. Twig

  11. 1. Installation & bootstrap 2. Twig for web designers 3.

    Twig for developers 4. Frameworks & CMS
  12. 1. Installation & bootstrap

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

  14. Extension Installation $ cd ext/twig $ phpize $ ./configure $

    make $ make install extension = twig.so
  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' ));
  16. 2. Twig for web designers

  17. Concise templating syntax

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

    do something ... %} {{ ... display something ... }}
  19. PHP compilation and cache

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

    {{ name }}!
  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
  22. Debugging

  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
  24. Dumping a Variable {% set names = ['John', 'Tom', 'Paul']

    %} {{ dump(names) }}
  25. Strict Variables Enabled Hello {{ nam }}! Twig_Error_Runtime: Variable "nam"

    does not exist in "hello.twig" at line 1
  26. Output escaping

  27. Automatic Output Escaping Hello {{ name }}! The variable is

    automatically escaped if it contains a string
  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') }}
  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
  30. Variables

  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.
  32. Variables Abstraction echo $article['title']; echo $article->title; echo $article->title(); echo $article->getTitle();

    echo $article->isTitle();
  33. Loops & Conditions

  34. Making Decisions {% if product.stock > 10 %} Available {%

    elseif product.stock > 0 %} Only {{ product.stock }} left! {% else %} Sold-out! {% endif %}
  35. Iterating Over a Collection <div class="posts"> {% for post in

    posts if post.active %} <h2>{{ post.title }}</h2> {{ post.body }} {% else %} No published posts yet. {% endfor %} </div>
  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
  37. Operators

  38. Operators o  Math: +, -, /, *, **, % o 

    Logical: or, and, xor o  Concatenation: ~ o  Comparison: <, >, <=, >=, == o  Containment: in, not in
  39. Functions

  40. Generating Contents Hello {{ random(['John', 'Tom', 'Paul']) }}! {% for

    i in range(0,10) %} {{ cycle(['odd', 'even'], i) }}<br/> {% endfor %}
  41. Built-in Functions o  attribute o  block o  constant o  cycle

    o  date o  parent o  random o  range
  42. Filters

  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') }}
  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
  45. Whitespace Control

  46. Whitespace Control {% spaceless %} <p> Hello <strong>{{ name }}</strong>!

    </p> {% endspaceless %} <p>Hello <strong>Hugo</strong>!</p>
  47. Whitespace Control <p> Hello <strong> {{- name }} </strong>! </p>

    <p>Hello <strong>Hugo </strong>!</p> Value is trimmed on the left.
  48. Template inclusion

  49. Template Inclusion {% include "list.twig" with { "section": "blog", "posts":

    articles } only %} The included template is rendered with its own context. Isolation
  50. Template inheritance

  51. layout.twig {% block body %} {% endblock body %} {%

    block breadcrumb %} ... {% endblock %} blog.twig {% extends "layout.twig" %} {% block breadcrumb %} {{ parent() }} - Blog {% endblock breadcrumb %} {% block body %} <h1>Latest posts</h1> {% include "posts.twig" %} {% endblock body %}
  52. {% extends "layout.twig" %} {% block breadcrumb %} {{ parent()

    }} - Blog {% endblock breadcrumb %} {% block body %} <h1>Latest posts</h1> {% include "posts.twig" %} {% endblock body %} Template Inheritance Extend the parent template. Reuse the parent block default value. Fill the parent body block.
  53. None
  54. Macros

  55. Defining Macros {% macro input(name, value, type, size) %} <input

    type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}" /> {% endmacro %} Default argument values are defined with the default filter
  56. Using Macros {% import "forms.html" as forms %} <p> {{

    forms.input('username') }} </p> Macros are imported under a specific namespace The macro is called with the prefixed namespace
  57. Sandboxed environment

  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'), );
  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);
  60. Using the Sandbox Mode {% sandbox %} {% include 'users.html'

    %} {% endsandbox %}
  61. Enabling Sandbox Mode $sandbox = new Twig_Extension_Sandbox($policy, true); Sandbox mode

    is automatically enabled for all template
  62. Enabling Sandbox Mode {% block foo 'bar' %} {% include

    'users.html' %} Twig_Sandbox_SecurityError: Tag "block" is not allowed in "hello.twig" at line 2
  63. 3. Twig for developers

  64. I want to customize Twig!

  65. Internal Architecture Lexer Parser Compiler Extension Extension Extensions Twig_Environment

  66. The Twig Lexer $template = <<<EOT Hello {{ name }}!

    EOT; $twig = new Twig_Environment(); $stream = $twig->tokenize($template);
  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(!) )
  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 }
  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, ));
  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
  71. Twig extensions

  72. Extending the Twig Gramar o  Global variables o  Global functions

    o  Filters o  Tests o  Operators o  T ags
  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
  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(); }
  75. Creating a Twig Extension class GravatarExtension extends \Twig_Extension { public

    function getName() { return 'gravatar'; } } The abstract getName() method must be implemented.
  76. Registering the Extension $extension = new GravatarExtension(); $twig = new

    Twig_Environment(); $twig->addExtension($extension); Easy uh?!
  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); } }
  78. Using the Global Function {% set uri = gravatar("hugo@example.com") %}

    <img src="{{ uri }}" alt="hhamon"/> Twig now knows this function.
  79. 4. Frameworks & CMS

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

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

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

    Yaml filters …
  83. Zend Framework 1 Ano_ZFTwig Automatic escaping Layout inheritance Javascripts helpers

    Stylesheets helpers Routing helpers https://github.com/benjamindulau/Ano_ZFTwig
  84. Zend Framework 2 Zfc_Twig Automatic escaping Layout inheritance Action rendering

    Forms helpers Events triggering https://github.com/ZF-Commons/ZfcTwig
  85. Drupal 7 Drupal themes Switch/Case tag I18n capabilities Extra filters

    Extra functions http://drupal.org/sandbox/ReneB/1075966
  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

  87. Questions ?

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

  89. Community Feedbacks

  90. Thank You!