If you’re here on purpose (1) and reading this blog post (2), then you’ve probably heard of Twig – the superfast, flexible and secure templating engine for PHP!?
Twig can be used in any PHP project but we’ll be looking at it specifically from a Symfony point of view. You see, Twig is to Symfony what Blade is to Laravel. If you are familiar with Java then probably, FreeMarker or Velocity are good comparisons to Twig, but in the PHP world.
Twig is quite intuitive and easy to learn and it’s API is very concise, which beats using raw PHP for templating. Also, what this means is that frontend devs and designers can easily learn Twig and use it to develop great looking and functional UIs.
What are Tags and how do we use them?
Template Inheritance and Hierarchy
Twig let’s you build your pages using special templates and, amongst other code constructs, it allows you to use special tags like ‘extends’ and ‘include’ to provision a kind of template inheritance. For example, you can have a main template (let’s call it base.html.twig) which contains the outer HTML (the non-dynamic stuff) structure to support all pages, and then, you can include different templates within it to take care of the dynamic stuff. A special tag exists in Twig called ‘include’ which allows you to include child templates inside another however a child template, being directly rendered from within a controller is only a representation of the inner ‘part’ of a page and needs the ‘base’ template to complete it. Here the child template will initially extend the base template before specifying it’s own specific content.
Extends & Block Tag
The way that this inheritance works, is that each page will render a template (e.g. ‘home.html.twig’) and inside this template, it’ll extend the base.html.twig template using a special tag called ‘extends’ in order to place itself inside the base.html.twig template thus completing the page. It achieves this by targeting predefined sections inside the parent template called ‘blocks’. These ‘blocks’ and defined using another special tag ‘block’, which can be used in a template as many times as needed. Anyway, going back to ‘home.html.twig’, if in your child template you specify a ‘block’ tag and add content within it, this will replace the content inside your parent template i.e. ‘base.html.twig’ at the position where the same ‘block’ is defined if at all.
Here is a simple example:
//base.html.twig
{% block main %}
This is some initial content
{% endblock %}
// home.html.twig
{% extends "base.html.twig" %}
{% block main %}
This content will replace the content in the 'main' block of base.html.twig template
{% include 'some_other_template.html.twig %}
{% endblock %}
How are Tags defined?
As this is not a full Introduction to Twig templating tutorial, we’ll leave the basics here. The above was simply to introduce the concept of tags in Twig and explain how a few of the main ones are used. Now, let’s dive more into tags.
You may already know that ‘extends’, ‘include’ and ‘block’ tags are just some examples of constructs in the Twig language which allow you to control content and structure in your views? What you may not know is that these are exposed by PHP classes or to put it more correctly, each ‘Tag’ is directly exposed via a PHP class which defines it and determines what it does. These classes are called TokenParser’s in Symfony. A Token Parser is defined for every Twig Tag you’ll ever use. Let’s take the ‘set’ Tag, used to defined and assign a value to a variable in Twig.
Examples below:
# examples
{% set foo = [1, 2] %}
{% set foo = {'foo': 'bar'} %}
{% set foo = 'foo' ~ 'bar' %}
This Tag has a token parser called SetTokenParser. Notice the word ‘Set’ used in the class name – this is the convention used in Symfony. Whatever your ‘Tag’ will be, (as used inside a Twig template) it will usually prefix ‘TokenParser’ when defining the class (i.e. SomethingTokenParser).
How about the ‘for’ tag, used to iterate over a list or array within Twig?
# example
{% for item in list %}
# do something
{% endfor %}
This one has a token parser called (you guessed it) ForTokenParser. A good reference for seeing all the different parsers included by Twig in a Symfony project is in the Twig\Extension\CoreExtension class.
A token parser implements Twig\TokenParser\TokenParserInterface which requires three methods to be implemented: these are parse(Token $token), setParser(Parser $parser) and getTag(). The parse() method parses a Token and returns a “Node” object. A “Token” object is a class of type Twig\Token which holds three private properties; $type, $value and $lineno. A “Token” is basically an object representation of a HTML tag contained within a twig file. It maintains a tag’s open tag name, close tag name (if necessary) and the line number it was found on. The “Node” is an object representation of a Node in the Abstract Syntax Tree (AST).
Okay, that’s somewhat a boring list low level facts about the Token Parsers inner workings so, what’s the point? How does Symfony identify and load the corresponding parser when rendering Twig templates containing various tags?
Let’s look at this more closely in part two of “Twig Tags – Under The Hood”.