Introduction to Twig

markstory 7,764 views 59 slides Nov 03, 2012
Slide 1
Slide 1 of 59
Slide 1
1
Slide 2
2
Slide 3
3
Slide 4
4
Slide 5
5
Slide 6
6
Slide 7
7
Slide 8
8
Slide 9
9
Slide 10
10
Slide 11
11
Slide 12
12
Slide 13
13
Slide 14
14
Slide 15
15
Slide 16
16
Slide 17
17
Slide 18
18
Slide 19
19
Slide 20
20
Slide 21
21
Slide 22
22
Slide 23
23
Slide 24
24
Slide 25
25
Slide 26
26
Slide 27
27
Slide 28
28
Slide 29
29
Slide 30
30
Slide 31
31
Slide 32
32
Slide 33
33
Slide 34
34
Slide 35
35
Slide 36
36
Slide 37
37
Slide 38
38
Slide 39
39
Slide 40
40
Slide 41
41
Slide 42
42
Slide 43
43
Slide 44
44
Slide 45
45
Slide 46
46
Slide 47
47
Slide 48
48
Slide 49
49
Slide 50
50
Slide 51
51
Slide 52
52
Slide 53
53
Slide 54
54
Slide 55
55
Slide 56
56
Slide 57
57
Slide 58
58
Slide 59
59

About This Presentation

No description available for this slideshow.


Slide Content

TWIG
Saturday, 3 November, 12

ABOUT ME
Team lead at FreshBooks
Lead Developer of CakePHP
Contributor to Twig
Saturday, 3 November, 12

WHAT IS IT
Templating language for PHP.
Uses syntax and ideas from jinja2.
Flexible and extensible at every layer.
Saturday, 3 November, 12

BUT PHP IS A
TEMPLATING
LANGUAGE DUMMY
Saturday, 3 November, 12

PHP SUCKS FOR TEMPLATING
// In Plain PHP
<?php echo $var; ?> (XSS you lose)
<?php echo htmlspecialchars($var, ENT_QUOTES, ‘UTF-8’); ?>
<?php echo h($var); ?> (sugar for htmlentities)
// In Twig - autoescaping enabled
{{ var }}
Saturday, 3 November, 12

BENEFITS OF TWIG
Terse syntax, and sugar.
Automatic HTML escaping.
Sandbox mode, which enables user editable templates.
Ability to create custom DSL’s using application tags, operators
and functions.
Saturday, 3 November, 12

PLAIN PHP VS TWIG
Saturday, 3 November, 12

CONDITIONALS
// In Plain PHP
<?php if (!empty($var): ?>
...
<?php endif; ?>
// In Twig
{% if var %}
...
{% endif %}
Saturday, 3 November, 12

LOOPS
<?php
if (!empty($var):
foreach ((array)$var as $i => $v):
printf(
‘%s : %s’,
htmlspecialchars($i, ENT_QUOTES, ‘UTF-8’),
htmlspecialchars($v, ENT_QUOTES, ‘UTF-8’));
endforeach;
else:
echo ‘No things’;
endif;
Saturday, 3 November, 12

LOOPS
{% for i, v in var %}
{{ i }} : {{ v }}
{% else %}
No things
{% endfor %}
Saturday, 3 November, 12

LOOPS
{% for user in users if user.active %}
{{ user.name }} : {{ user.email }}
{% else %}
No active users
{% endfor %}
Saturday, 3 November, 12

BUT WAIT THERE IS
MORE
Saturday, 3 November, 12

AWESOME++
Macros.
Blocks & extending templates.
Saturday, 3 November, 12

MACROS
{% macro username(user) %}
<a href=”{{ url({
‘controller’: ‘users’,
‘action’: ‘view’,
user.username) }}”>
<span class=”user-first-name”>
{{ user.first_name }}
</span>
<span> class=”user-last-name”>
{{ user.last_name }}
</span>
</a>
{% endmacro %}
Saturday, 3 November, 12

IMPORTING MACROS
// import all the macros
{% import ‘/import/formatting.twig’ as formatting %}
{{ formatting.username(user) }}
// import one macro
{% from ‘/import/formatting.twig’ import username %}
{{ username(user) }}
// import one & alias it.
{% from ‘/import/formatting.twig’ import username as un %}
{{ un(user) }}
Saturday, 3 November, 12

INHERITANCE & BLOCKS
Extending views & blocks work hand in hand.
Blocks are like slots or holes in a template, that the child can fill.
Blocks can be used out of order, which is pretty sweet.
Blocks can be imported from other templates, similar to traits.
Saturday, 3 November, 12

INHERITANCE
{# layout/base.twig #}
Company X - Official Email template
{% block content ‘Super important’ %}
Copyright 2012
Saturday, 3 November, 12

INHERITANCE
{# email/winner.twig #}
{% extend ‘/layout/base.twig’ %}
{% block content %}
To whom it may concern,
You win!
{% endblock %}
Saturday, 3 November, 12

INHERITANCE
{# email/winner.twig #}
{% extend ‘/layout/base.twig’ %}
{% block content %}
To whom it may concern,
{{ parent() }} You win!
{% endblock %}
Saturday, 3 November, 12

INHERITANCE TIPS
Don’t use {% block %} inside a loop. It doesn’t do what you
want.
You can use {{ block(name) }} to dynamically call blocks.
Saturday, 3 November, 12

EXTENDING TWIG
TWIG EXTENSIONS
Saturday, 3 November, 12

EXTENDING TWIG
Twig can be extended in several ways.
Filters, Functions, Globals, Tests, Operators, TokenParsers,
NodeVisitors.
You should use extensions to package up your enhancements.
Saturday, 3 November, 12

TWIG EXTENSIONS
Saturday, 3 November, 12

LOADING EXTENSIONS
$loader = new Twig_Loader_FileSystem (APP . ‘/templates’);
$twig = new Twig_Environment($loader, $options);
$twig->addExtension(new App_Extension_Url());
Saturday, 3 November, 12

ENVIRONMENT FACTORY
class AppTwig {
static function loadTemplate($template, $options = array()) {
$loader = new Twig_Loader_FileSystem (APP . ‘/templates’);
$twig = new Twig_Environment($loader, $options);
$twig->addExtension(new App_Extension_Url());
// Load more extensions
return $twig->loadTemplate($template);
}
}
$template = AppTwig::loadTemplate(‘/users/profile.twig’ );
Saturday, 3 November, 12

EXTENSION EXAMPLE
<?php
class App_Extension_Url extends Twig_Extension {
public function getName() {
return ‘app.url’;
}
public function getFilters() {
return array(
‘name’ => new Twig_Filter_Method($this, ‘formatName’),
);
}
}
Saturday, 3 November, 12

GLOBALS
Can be used to expose application or framework objects.
Great for migrating an older codebase to use Twig.
E.g {{ html.link(...) }}
Saturday, 3 November, 12

FUNCTIONS
Global functions added to a template context.
Great for providing shortcuts to application features, like url
generation or built-in PHP functions.
Example {{ form_input(model, ‘name’) }}
Saturday, 3 November, 12

FILTERS
Filters are intended for simple formatting functions.
The filtered variable is the first argument to the filter function.
Filters can have additional arguments as well.
Example: {{ invoice.amount|currency(‘CAD’) }}
Saturday, 3 November, 12

TESTS
Allow you to implement custom conditional logic. In an
expressive manner with domain objects.
Value being compared is supplied as the first argument. Other
arguments follow.
{% if user is paying %}
{% if number is divisibleby(3) %}
Saturday, 3 November, 12

NODE VISITORS
Allows you to visit each node in the Abstract syntax tree.
Applied before template is compiled.
Commonly used for optimizing the AST, or applying
transformations to, or reading data from nodes in the tree.
Saturday, 3 November, 12

CUSTOM TAGS
Saturday, 3 November, 12

TWIG INTERNALS
LOADER
ENVIRONMENT
Saturday, 3 November, 12

TWIG INTERNALS
LOADER
LEXERENVIRONMENT
Saturday, 3 November, 12

TWIG INTERNALS
LOADER
LEXERENVIRONMENT
TOKENS
Saturday, 3 November, 12

TWIG INTERNALS
LOADER
LEXERENVIRONMENT
TOKENS
PARSER
Saturday, 3 November, 12

TWIG INTERNALS
LOADER
LEXERENVIRONMENT
TOKENS
PARSER
NODES
Saturday, 3 November, 12

TWIG INTERNALS
LOADER
LEXERENVIRONMENT
TOKENS
PARSER COMPILER
NODES
Saturday, 3 November, 12

TWIG INTERNALS
LOADER
LEXERENVIRONMENT
TOKENS
PARSER COMPILER
NODES
PHP CODE
Saturday, 3 November, 12

TOKEN PARSERS
Used to implement custom tags or DSL features.
The most complex feature to add.
Each tag is composed of two parts:
TokenParser - parses the tag and validates its syntax.
Node - Added to the AST and compiles the PHP code used
in templates.
Saturday, 3 November, 12

TAG EXAMPLE
{% debug %}
{% debug my_var %}
{% debug 2 > 1 %}
Saturday, 3 November, 12

TOKEN PARSER
class App_TokenParser_Debug extends Twig_TokenParser {
public function parse(Twig_Token $token) {
$line = $token->getLine();
$expr = null;
if (!$this->parser->getStream()->test( Twig_Token::BLOCK_END_TYPE)) {
$expr = $this->parser->getExpressionParser->parseExpression();
}
$this->parse->getStream()->expect( Twig_Token::BLOCK_END_TYPE);
return new App_Node_Debug($expr, $line, $this->getTag());
}
}
Saturday, 3 November, 12

NODE COMPILER
class App_Node_Debug extends Twig_Node {
public function __construct( Twig_Node_Expression $ex, $line, $tag) {
parent::__construct(array(‘expr’ => $ex), $line, $tag);
}
public function compile(Twig_Compiler $compiler) {
$compiler->write(‘if ($this->env->isDebug()) {‘ );
if ($this->getNode(‘expr’) === null) {
// Print all vars.
} else {
$compiler->write(‘var_dump(‘)
->subcompile($this->getNode(‘expr’))
->raw(‘);’);
}
$compiler->write(‘}’);
}
}
Saturday, 3 November, 12

OPERATORS
Allow you to add additional boolean operators.
I’ve never used this feature.
Saturday, 3 November, 12

DEPLOYING TWIG
Saturday, 3 November, 12

TWIG IN PRODUCTION
FreshBooks (the app, not the website).
520+ templates.
Twig templates are used for almost all HTML & E-mail content.
Saturday, 3 November, 12

TEMPLATE COMPILATION
TWIG
Saturday, 3 November, 12

TEMPLATE COMPILATION
TWIG
PHP
Saturday, 3 November, 12

TEMPLATE COMPILATION
TWIG
PHP
HTML
Saturday, 3 November, 12

TEMPLATE COMPILATION
TWIG
PHP
HTML
Saved to disk
Saturday, 3 November, 12

TEMPLATE COMPILATION
PHP
HTML
Saved to disk
Saturday, 3 November, 12

HOW WE DEPLOY
Saturday, 3 November, 12

HOW WE DEPLOY
COPY
FILES
Saturday, 3 November, 12

HOW WE DEPLOY
COPY
FILES
COMPILE
/ BUILD
Saturday, 3 November, 12

HOW WE DEPLOY
COPY
FILES
COMPILE
/ BUILD
SYMLINK
Saturday, 3 November, 12

PRECOMPILE SCRIPT
$directory = new RecursiveDirectoryIterator ($argv[0]);
$recurser = new RecursiveIteratorIterator ($directory);
$matcher = new RegexIterator(
$recurser,
'/.*?\.twig$/',
RegexIterator::GET_MATCH);
echo "Compiling Templates" ;
$i = 0;
foreach ($matcher as $file) {
$filename = str_replace($argv[1], '', $file[0]);
AppTwig::loadTemplate('/' . $filename);
echo '.';
$i++;
}
echo "Templates compiled" ;
exit(0);
Saturday, 3 November, 12

TWIG C EXTENSION
You can also install ext/twig.
This pushes the most frequently used method
Twig_Template::getAttribute() into C which increases
performance considerably.
The C extension is in the Twig repository.
Saturday, 3 November, 12

QUESTIONS?
Saturday, 3 November, 12

THANKS
@MARK_STORY
HTTP://MARK-STORY.COM
Saturday, 3 November, 12