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

Twig and Drupal, Drupal Camp Gent 2012

Twig and Drupal, Drupal Camp Gent 2012

Introduction to Twig, how you can use it within Drupal 7. This time with a little speed test and more on how to extend Twig with your own filters.

Rene Bakx

May 26, 2012
Tweet

More Decks by Rene Bakx

Other Decks in Programming

Transcript

  1. About me • René Bakx (@renebakx http://renebakx.nl) • PHP Developer

    since 2000 • user 590180 on drupal.org • Loves open source development • Hates the default HTML output of drupal 2 2 Saturday, May 26, 12
  2. 3 About Twig • Originally created by Armin Ronacher (Also

    known for Jinja, a Python template engine) • Since 2009 part of Fabien Potencier’s world domination plan aka Symfony2 • Twig is a very modern PHP 5 based template engine. • It is fast! Templates are compiled into PHP • It is secure! Templates can be sandboxed, output can be escaped. • It is extensible! You override everything if you want. 3 Saturday, May 26, 12
  3. 4 What is so good about it? • It is

    for HTML, what LESS/SASS is for CSS. • Object Oriented Templates (DRY!) • Integrates seamless into many IDEs like : Textmate, Sublime Text, Vim, Netbeans, PHP- Storm, Eclipse, Coda and many others. 4 Saturday, May 26, 12
  4. 5 Drupal and Twig • Started about 2 years ago

    as a spare time proof of concept project for @zichtonline. • Because we did not like PHPTemplate and the way output is handled in Drupal • Enforces separation of display and pre/post- processing logic. • BUT.. it’s not the holy grail solution for the ‘array of doom’ problem! 5 Saturday, May 26, 12
  5. {# Comment #} {{ node.title }} {{ node.taxonomy|join(‘, ‘) }}

    {% for item in node.items %} {{ node.title }} {% endfor %} {% for i in range(0,3) %} - {{ i }} - {% endfor %} 7 Template logic 7 Saturday, May 26, 12
  6. {{ node.title }} Output that value of any of the

    following PHP or Drupal types: $node[‘title’] $node->title $node->title() $node = array(‘#theme’ => ‘theme_title’, ‘value => ‘My Title’)) 8 Template logic 8 Saturday, May 26, 12
  7. {{ node.taxonomy|join(‘, ‘) }} {{ node.taxonomy|join(‘, ‘)|title}} {% filter upper

    %} this text becomes uppercase {% endfilter %} Filters are use to modify variables or output. They can be chained with a | @see http://twig.sensiolabs.org/doc/filters/index.html 9 Template logic 9 Saturday, May 26, 12
  8. {% if user.id >= 1 %} {% for item in

    node.items %} {{ node.title }} {% endfor %} {% endif %} Control structures, called TAGS can be used to control the flow of your output. @see http://twig.sensiolabs.org/doc/tags/index.html 10 Template logic 10 Saturday, May 26, 12
  9. {% for i in range(0,3) %} - {{ i }}

    - {% endfor %} {{ random(node.taxonomy.terms }} Functions, can be used to generate content @see http://twig.sensiolabs.org/doc/functions/index.html 11 Template logic 11 Saturday, May 26, 12
  10. {% for node,comments in content.comments %} <h2>{{ loop.index }} -

    {{ node.title }}</h2> {% for comment in comments %} <h3>{{ comment.title }}</h3> <p>{{ comment.body }}</p> {% endfor %} {% endfor %} 13 Nested loops 13 Saturday, May 26, 12
  11. {# page.tpl.twig #} {% block header %} <header> .... </header>

    {% endblock %} {% block page %} <article> .... </article> {% endblock %} {% block footer %} <footer> .... </footer> {% endblock %} 14 Template inheritance 14 Saturday, May 26, 12
  12. {# page--404.tpl.twig #} {% extends ‘page.tpl.twig’ %} {% block page

    %} <h1>#fail!</h1> <p>Dude where’s my page?</p> {% endblock %} You only need to write the part that is CHANGED. No need to duplicate code between pages, nodes, blocks etc. etc. 15 Template inheritance (DRY!) 15 Saturday, May 26, 12
  13. {# page--mobile.tpl.twig #} {% extends vars.mobi ? ‘mobile.tpl.twig’ : ‘page.tpl.twig’

    %} {% block page %} <article>......</article> {% endblock %} Allows you to define one base template for mobile and one for other pages. Just set the mobi in page_preprocess() and your done. 16 Selective inheritance 16 Saturday, May 26, 12
  14. {% for block in content.blocks %} {% include ‘block_’ ~

    block.name ~ '.twig.tpl' %} {% endfor %} {% include ‘block_’ ~ block.name|default('base') ~'.twig.tpl' Write once, use multiple times by chunking the parts of the code you use all over your theme into includes instead of php methods. 17 Dynamic includes 17 Saturday, May 26, 12
  15. {# macro.form.tpl.twig #} {% macro field(name, value, type, size) %}

    <input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}"> {% endmacro %} {% import ‘macro.form.tpl.twig’ as form %} <p> {{form.field(‘password’,null,‘password’}} </p> Macros are not PHP functions but re-usable pieces of view logic, but they only can use the variables passed to them NO GLOBALS. 18 Macros 18 Saturday, May 26, 12
  16. Installation • The easiest way is using the drush make

    file from http://drupal.org/project/1528480/ • Or download all components yourself (some assembling required) Drupal http://drupal.org/download Twig https://github.com/fabpot/Twig/ TFD http://drupal.org/sandbox/ReneB/ 1075966 20 20 Saturday, May 26, 12
  17. Drupal addons: WITH {# macro.form.tpl.twig #} {% with title as

    title, elements sandboxed %} <h1>{{title}}</h1> <div> {{elements}} </div> {% endwith %} Join elements into a new context and remove the others from the view. Can be very useful to make the array of doom a bit more readable. 21 21 Saturday, May 26, 12
  18. Drupal addons: SWITCH {% switch page.regions %} {% case 'header

    %} {% include 'header.tpl.html' %} {# no break needed, as this default behaviour #} {% case 'content' fallthrough %} {# do something and fall trough to next case #} {% endswitch %} A switch, case construct just like PHP has. Can be useful to prevent endless amounts of IF / ELSEIF constructions. 22 22 Saturday, May 26, 12
  19. Drupal RENDER’n’HIDE {# hide comments and author #} {{ node.comments|hide

    }} {{ node.author|hide }} {# render node #} {{ node|render }} BUT... render is obsolete, since Twig for Drupal is smart enough to detect a render array of doom (tm) 23 {# hide comments and author #} {{ node.comments|hide }} {{ node.author|hide }} {# render node #} {{ node }} 23 Saturday, May 26, 12
  20. Adding your own filters function mymodule_hook_twig_filter(&$filters){ $filters[‘yourfilter’] = new Twig_Filter_Function(‘filter’);

    } function filter($value,$param){ /** $value contains the value the filter is called on $param contains a parameter of the filter } 24 {{ block.variable|yourfilter(‘param’) }} twig_getinstance()->addFilter(‘yourfilter’, new Twig_Filter_Function(‘filter’)); Using the hook_twig_filters() Or adding them directly Using them remains the same! 24 Saturday, May 26, 12
  21. Speed comparison 25 Same node matching template code on Macbook-pro

    2.2Ghz with MAMP 2.0.2 no APC TWIG Compile Twig Render PHP Template 0 100 200 300 400 225 ms 267 ms 372 ms 25 Saturday, May 26, 12
  22. Speed comparison 26 Same node matching template code on Macbook-pro

    2.2Ghz with MAMP 2.0.2 with APC TWIG Compile Twig Render PHP Template 0 75 150 225 300 119 ms 130 ms 234 ms Template cache was deleted after the first hit, to rule out time to compile all other code into APC. 26 Saturday, May 26, 12
  23. name = twiggy description = My first twig based theme

    engine = twig core = 7.x But I need to convert all the existing templates for all the modules every build including core into .twig.tpl files first! 28 Your first Twig theme 28 Saturday, May 26, 12
  24. name = twiggy description = My first twig based theme

    engine = twig core = 7.x But I need to convert all the existing templates for all the modules every build including core into .twig.tpl files first! 29 Your first Twig theme 29 Saturday, May 26, 12
  25. name = twiggy description = My first twig based theme

    engine = twig core = 7.x But I need to convert all the existing templates for all the modules every build including core into .twig.tpl files first! NOPE Not needed! 29 Your first Twig theme 29 Saturday, May 26, 12
  26. - if (isset($themes[$base_key]->info['engine'])) { + if (isset($themes[$base_key]->info['engine']) && $themes[$base_key]->info['engine'] ==

    $themes[$key]- >info['engine']) { $themes[$key]->info['engine'] = $themes[$base_key]- >info['engine']; $themes[$key]->owner = $themes[$base_key]->owner; $themes[$key]->prefix = $themes[$base_key]->prefix; Issue is filed, but stuck in the queue @see http://drupal.org/node/1545964 30 • Drupal 7 is supposed to be smart enough to detect wether a .tpl.twig exists and if not, it renders tpl.php • And in most cases it is, except when you extend a phptemplate based theme. • Only then you need a simple core patch Your first Twig theme 30 Saturday, May 26, 12