Twig: Friendly Curly Braces Invade Your Templates!
-
Upload
ryan-weaver -
Category
Technology
-
view
796 -
download
1
description
Transcript of Twig: Friendly Curly Braces Invade Your Templates!
Being dangerous with Twig
A guide to using Twig – the fast, secure andextensible PHP templating engine – to create clean
template code, leverage powerful filters, make your designerswrite you love letters, write template functions that Don't clog up your
global PHP namespace, take advantage of true template inheritance, hang out with Django programmers and be able to talk template syntax, enjoy true and non-invasive output escaping, have more time for your family, control whitespace, add global
variables to all templates, stop lying when you try to tell yourself that <?php echo looks better than asimple {{, use the fancy for-else control, Rock some macros – little reusable code functions, do awesome stuff like “{% if i is divisibleby 2 %}”,mediate in the simplicity of your templates and drink more green tea, sandbox your template and whitelist capabilities – allowing Twig to be used in a CMS,
take advantage of the fact that all templates compile to PHP classes that can extend a base class of your choosing, impress your friends by changing the print tag from{{ var }} to [all-your-base] var [are-belong-to-us], confuse the guy next to you by changing “is” and “is not” to mean the opposite things and convince him that he's misunderstood
how logical expressions are used in programming languages all along, create a custom tag that takes the body of its block and tweets it,write templates the expresses presentation and not program logic.
Being dangerous with Twig
KnpUniversity.comgithub.com/weaverryan
• Lead for the Symfony documentation!
• KnpLabs US - Symfony consulting, training, Kumbaya!
• Writer for KnpUniversity.comscreencasts
Buenos Dias!
Birthday Wishes!
Happy Birthday Dad!
Happy Birthday Anne-Sophie!
Happy Birthday Rafael Nadal
Happy Birthday Anderson Cooper
Why Twig?
Act 1
@weaverryan
because template engines are awesome
@weaverryan
$engine = new RyansFantasyTemplatingEngine();$tpl = $engine->loadTemplate('drupalcon.php'); $tpl->render([‘place' => ‘Austin!’]);
<!-- drupalcon.php --><h1><?php echo $place ?></h1><?php echo call_some_great_helper('woot!') ?>
Template Engines
• A template engine allows you to render a presentation (HTML, XML, etc) via a template in a controlled environment!
• It should allow special functionality that makes creating templates easier (helpers, template inheritance, etc)
@weaverryan
@weaverryan
a template engine is a tool
@weaverryan
why not just render PHP templates?
PHP templating woes
• rendering template files is a hack: an include statement with output-buffering control
!
• no or faked template inheritance!
• no isolation: PHP templates suck in any global variables or functions available
@weaverryan
@weaverryan
we want the brevity of templates
!
with the isolation of object-oriented programming
@weaverryan
so give me some Twiggy pudding
Twig is:» fast» flexible» concise» secure» fully-featured» Extensible» designer-friendly
Twig offers:» true inheritance» real output escaping» tons of filters» custom tags» great documentation» global variables» the “for-else” control
@weaverryan
Twig is concise !
and each template compiles to an actual
PHP object
@weaverryan
Seeing is believing
https://www.flickr.com/photos/visitfinland/5203910918
@weaverryan
because template engines are awesome
@weaverryan
because template engines are awesome
@weaverryan
because template engines are awesome
class __TwigTemplate_617db133b9dd01ce28b55447b extends Twig_Template{ // line 3 public function block_body($context, array $blocks = array()) { // line 4 echo " "; foreach ($context['_seq'] as $context["_key"] => $context["blog"]) { // line 5 echo " <h2>"; echo $this->getAttribute($context["blog"]); echo "</h2>
@weaverryan https://www.flickr.com/photos/melolou/517629486
a moment of templating zen
@weaverryan
“The template system is meant to express presentation, not
program logic.”- Django Documentation
@weaverryan
Twig can easily be used anywhere
@weaverryan
require __DIR__.'/vendor/autoload.php'; $loader = new Twig_Loader_Filesystem(array(__DIR__.'/templates'));$twig = new Twig_Environment($loader); echo $twig->render('hello.twig', array( 'name' => 'DrupalCon!'));
{# templates/hello.twig #} {% extends 'layout.twig' %}{% block body %} Hello {{ name }}!{% endblock %}
Act 2
Twig’s Simple Life
@weaverryan
Twig's three tags
Twig parses just three tags:!
» comment tag!
» print tag!
» block tag
a. do nothing (comment tags)
{# comment #}» totally ignored when rendered
@weaverryan
b. say something (print tags)
{{ 'print me!' }}» simply prints the given expression» equivalent to <?php echo» If you're ultimately printing something,
use this tag
@weaverryan
@weaverryan
c. do something (block tags)
{% set foo = 'inside a block tag' %}» used mostly for control-flow statements like if,
for, include and block» can have beginning and end tags» if you're *doing* something and not *printing*
something, use this tag
@weaverryan
Twig’s three tags
!
» do nothing: {# comment tag #}» say something {{ ‘print tag’ }}» do something {% block tag %}
It’s just that simple!
Act 3
Everything is an expression
@weaverryan
expressions Twig guts
» like PHP, most everything inside a tag is an expression!
!
!
!
!
» expressions are the most interesting and flexible part of Twig
@weaverryan
Expressions Block names Block-specific tokens
@weaverryan
An expression can consist of many different things
https://www.flickr.com/photos/swambo/7617988518
@weaverryan
strings, numbers and variables
» like any language, strings, numbers and variables are commonplace
@weaverryan
arrays and hashes
» arrays use [], hashes use {}
@weaverryan
operators
» just like PHP operators, but extensible
@weaverryan
filters
» filters modify the value that precedes it and are always preceded by a pipe (|)
» filters may or may not take arguments
@weaverryan
functions
» returns a value based on an arbitrary input
@weaverryan
» strings, numbers and variables » arrays and hashes » operators » filters » functions
allow Twig to express Twig’s-self
Hey! It’s simple like PHP, but flexible
Act 4
Twig on the battlefield
@weaverryan
» a template that displays a list of “widgets” in odd-even rows
» render info about each widget
» create basic, clean pagination
the test…
@weaverryan
@weaverryan http
://1.
bp.b
logs
pot.c
om/_
D_Z-
D2tz
i14/
TBpO
nhVq
yAI/A
AAAA
AAAD
FU/8
tfM4E
_Z4p
U/s
1600
/resp
onsi
bilit
y12(
alte
rnat
e).p
ng
@weaverryan
@weaverryan
» the “truncate” filter isn't part of Twig, but is available via a library of extensions
» Everything in Twig is loaded via an Extension (even the core stuff)
» Extensions are easy to use and create – we’ll prove it later!
» https://github.com/fabpot/Twig-extensions
your presenter is lying to you…
@weaverryan http
://1.
bp.b
logs
pot.c
om/_
D_Z-
D2tz
i14/
TBpO
nhVq
yAI/A
AAAA
AAAD
FU/8
tfM4E
_Z4p
U/s
1600
/resp
onsi
bilit
y12(
alte
rnat
e).p
ng
@weaverryan
@weaverryan https://www.flickr.com/photos/circasassy/7192588208
Flex some filters
@weaverryan
@weaverryan
convenience, readability
@weaverryan
@weaverryan
pagination?
@weaverryan
@weaverryan
» but.... the “radius” function doesn't actually exist in Twig.
the audacity: your speaker just lied again
But since it's pretty handy, let's create it!
Act 5
Twig extensions!
@weaverryan
» filters» functions» operators» tests (e.g. divisibleby)» custom tags
Twig extensions
everything in Twig is loaded by an “Extension” class:
Extensions are easy!
@weaverryan
@weaverryan
Yes, there is a missing piece of “hooking this up”
@weaverryan
It’s a small amount of code, involving services
@weaverryan
Come to my talk tomorrow ;)
!
MASTER THE NEW CORE OF DRUPAL 8 NOW: WITH SYMFONY
AND SILEX !
10:45 Room: G - Trellon | 4th floor
Act 6
Theming D7 versus D8
@weaverryan
Good News!
@weaverryan
The Changes are Underwhelming!
@weaverryan
From D7 themes to D8 themes
» Other than the Twig syntax, things feel very familiar!
» page.tpl.php -> page.html.twig» node.tpl.php -> node.html.twig» THEME.info -> THEME.info.yml !
» THEME_field__taxonomy_term_reference() -> field--taxonomy-term-reference.html.twig
@weaverryan
<div id="node-<?php print $node->nid; ?>" clearfix"<?php print $attributes; ?>> <?php print render($title_prefix); ?> <div class="content clearfix"<?php print $content_attributes; ?>> <?php hide($content['links']); print render($content); ?> </div> <?php $links = render($content['links']); if ($links): ?> <div class="link-wrapper"> <?php print $links; ?> </div> <?php endif; ?> </div>
D7: node.tpl.php
@weaverryan
<article id="node-{{ node.id }}” role=“article" {{ attributes|without(‘id', 'role') }}> <header>{{ title_prefix }}</header> <div class="content clearfix"{{ content_attributes }}> {{ content|without('links') }} </div> {% if content.links %} <footer class="link-wrapper"> {{ content.links }} </footer> {% endif %}</article>
D8: node.html.twig
@weaverryan
Function overrides
@weaverryan
D7: template.php
function bartik_field__taxonomy_term_reference($variables) { $output = ''; // Render the label, if it's not hidden. if (!$variables['label_hidden']) { $output .= '<h3 class="field-label">' . $variables['label'] . ': </h3>'; } // Render the items. $output .= ($variables['element']['#label_display'] == 'inline') ? '<ul class="links inline">' : '<ul class="links">'; foreach ($variables['items'] as $delta => $item) { $output .= '<li class="taxonomy-term-reference-' . $delta . '"' . $variables['item_attributes'][$delta] . '>' . drupal_render($item) . '</li>'; } $output .= '</ul>';
@weaverryan
D8: field--taxonomy-term-reference.html.twig
<div class="{{ attributes.class }} clearfix” {{ attributes|without('class') }}> <h3{{ label_attributes }}>{{ label }}: </h3> <ul class="links"> {% for delta, item in items %} <li class="taxonomy-term-reference-{{ delta }}"{{ item_attributes[delta] }}>{{ item }}</li> {% endfor %} </ul> </div>
Act 7
after-dinner mint
Mmmmm…..
@weaverryan
Debugging
@weaverryan
/** * settings.php * * Twig debugging: * * When debugging is enabled: * - The markup is surrounded by HTML comments * - The dump() function can be used * - Templates are automatically recompiled */$settings['twig_debug'] = TRUE;
@weaverryan
… inline suggestions about the template to override …
@weaverryan
… dump *all* variables you have access to …
@weaverryan
<article id="node-{{ node.id }}" ...> {{ dump() }} {# ... #}</article>
@weaverryan
… or just dump the names of the variables …
@weaverryan
<article ...> {{ dump(_context|keys) }} </article>
@weaverryan
Inheritance
@weaverryan
{% block header %}<header> {{ title_prefix }} {% if not page %} <h2{{ title_attributes }}> <a href="{{ node_url }}">{{ label }}</a> </h2> {% endif %} {{ title_suffix }} {% if display_submitted %} <div class="meta submitted"> {{ user_picture }} {{ submitted }} </div> {% endif %}</header>{% endblock %}
node.html.twig
@weaverryan
{% extends "core/themes/bartik/templates/node.html.twig" %}{% block header %} <h1 class="header">{{ label }}</h1>{% endblock %}
node--article.html.twig
@weaverryan
{% extends "core/themes/bartik/templates/node.html.twig" %}{% block header %} <div class="article"> {{ parent() }} </div>{% endblock %}
node--article.html.twig
@weaverryan
dot.notation
@weaverryan
Am I working with an array?
<?php print render($page['header']); ?>
<div id="node-<?php print $node->nid; ?>">
or an object?
@weaverryan
Am I working with an array?
who cares!?
<article id="node-{{ node.id }}">
{{ page.header }}
@weaverryan
{{ page.header }}
» The dot notation is smart!!
A. Is this an object with a public property?B. Is this an array that has this key?C. Is there a getHeader() function I can call?
@weaverryan
Templates in the Database
@weaverryan
Twig.js
@weaverryan
A twig template can *also* be rendered in
JavaScript
@weaverryan
<script src="/js/twig.js"> <script> var template = twig({ data: 'The {{ baked_good }} is a lie.' }); console.log( template.render({ baked_good: ‘cupcake' }) ); // outputs: "The cupcake is a lie."</script>
@weaverryan
https://github.com/justjohn/twig.js/
Ryan Weaver @weaverryan
¡Gracias!