a Sensio Labs Product

The flexible, fast, and secure
template language for PHP

Twig migration to Git

I have just switched from using Subversion as the main repository for Twig to Git.

This change is transparent for Twig users. Before, the Subversion repository was mirrored to Git every 15 minutes. Now, this is just the other way round. It means that I commit to Git instead of Subversion.

I have also migrated the ticketing system from Trac to Git.

Twig 0.9.5 released

I’m proud to announce the immediate availability of Twig 0.9.5.

Before upgrading from 0.9.4, read this post carefully as this new release might break your existing code.

The documentation has been updated to reflect the changes made in this new version. We have also enhanced the documentation based on the feedback we had.

New Features

.. Operator

One of the main frequently asked question was about iterating over a range of integer. Thanks to the new .. operator, this is now really easy to accomplish:

{% for i in 0..10 %}
  * {{ i }}
{% endfor %}

The above snippet of code prints all numbers from 0 to 9.

The left and right side of the .. operator can be any valid expression:

{% for letter in 'a'..'z' %}
  * {{ letter }}
{% endfor %}

{% for letter in 'a'|upper..'z'|upper %}
  * {{ letter }}
{% endfor %}

Note that the .. operator is just syntactic sugar for the range filter. The first example is equivalent to the following:

{% for i in 0|range(10) %}
  * {{ i }}
{% endfor %}

Array Support

Twig supports a new literal: arrays. Arrays are defined by a sequence of expressions separated by a comma (,) and wrapped with squared brackets ([]). Arrays can also be nested as much as needed:

{% set foo as [a, 'b', ['c', 'd']] %}

Like in PHP, arrays are a mix between lists and dictionaries, arrays and hashes:

{% set foo as ['a': 'a', 'b': 'c'] %}

in Operator

The in operator performs a containment test. It returns true if the left operand is contained in the right one:

{{ 1 in [1, 2, 3] }}
{# returns true #}

{% if current_user in users %}
  {# do something #}
{% endif %}

To perform a negative test, the whole expression should be prefixed with not:

{{ not 1 in [1, 2, 3] }}
{# returns false #}

The in operator is just syntactic sugar for the in filter. The first example is equivalent to the following:

{{ 1|in([1, 2, 3]) }}

Better Filter System

The filter system has been rework to allow for more flexibility. For instance, You can now easily bundle your filters in your extension class:

class Project_Twig_Extension extends Twig_Extension
{
  public function getFilters()
  {
    return array(
      'rot13' => new Twig_Filter_Method($this, 'rot13Filter'),
    );
  }

  public function rot13Filter($string)
  {
    return str_rot13($string);
  }

  public function getName()
  {
    return 'project';
  }
}

include tag

You can now explicitly pass variables when including another template:

{% include 'foo' with ['foo': foo] %}

The with option can be combined with the sandboxed one to allow for very secure templates:

{% include 'foo' sandboxed with vars %}

Speed improvements

This new version of Twig is faster than any other Twig version. The speed gain depends on your templates of course.

For even more speed, you can now disable the automatic creation of the loop variable in a for loop:

{% for i in 0..10 without loop %}
  * {{ i }}
{% endfor %}

Miscellaneous

This version also has many other small improvements. The full changelog read as follows:

  • fixed list nodes that did not extend the Twig_NodeListInterface
  • added the “without loop” option to the for tag (it disables the generation of the loop variable)
  • refactored node transformers to node visitors
  • fixed automatic-escaping for blocks
  • added a way to specify variables to pass to an included template
  • changed the automatic-escaping rules to be more sensible and more configurable in custom filters (the documentation lists all the rules)
  • improved the filter system to allow object methods to be used as filters
  • changed the Array and String loaders to actually make use of the cache mechanism
  • included the default filter function definitions in the extension class files directly (Core, Escaper)
  • added the // operator (like the floor() PHP function)
  • added the .. operator (as a syntactic sugar for the range filter when the step is 1)
  • added the in operator (as a syntactic sugar for the in filter)
  • added the following filters in the Core extension: in, range
  • added support for arrays (same behavior as in PHP, a mix between lists and dictionaries, arrays and hashes)
  • enhanced some error messages to provide better feedback in case of parsing errors

Backwards Incompatibilities

Custom Filters

If you have defined custom filters, you MUST upgrade them for this release.

Before 0.9.4, filters were defined with a simple array like this:

// before
'even'   => array('twig_is_even_filter', false),
'escape' => array('twig_escape_filter', true),

As of 0.9.5, a filter is defined as an object and the needs_environment option replaces the Boolean:

// after
'even'   => new Twig_Filter_Function('twig_is_even_filter'),
'escape' => new Twig_Filter_Function('twig_escape_filter', array('needs_environment' => true)),

NodeTransformers

If you have created NodeTransformer classes, you will need to upgrade them to the new interface. Read the built-in transformers classes to learn more about this topic.

Upgrading

Upgrading can be done in a few easy steps:

  • Install the new version (via PEAR, SVN, Git, or by downloading the new package);

  • Read the previous section about backward incompatibilities, and upgrade your code accordingly;

  • Remove all cached templates;

  • Test.

Twig 0.9.4 released

Twig 0.9.4 has just been released.

If you have custom loaders, you MUST upgrade them for this release: The Twig_Loader base class has been removed, and the Twig_LoaderInterface has also been changed (see the source code for more information or the online documentation, which has been updated).

The complete changelog reads as follow:

  • added support for DateTime instances for the date filter
  • fixed loop.last when the array only has one item
  • made it possible to insert newlines in tag and variable blocks
  • fixed a bug when a literal ‘\n’ were present in a template text
  • fixed bug when the filename of a template contains */
  • refactored loaders

Twig 0.9.3 released

I have just released Twig 0.9.3.

This release dramatically improves the performance of loops. It’s also the first backward incompatible release since the beginning of the project.

Loops are also much more easier to use as the items filters is not needed anymore:

{# before 0.9.3 #}
{% for k, v in values|items %}

{# as of 0.9.3 #}
{% for k, v in values %}

The previous template still work as items is now a noop filter. So, you can safely removed it

The loaders do not take the cache and autoReload arguments anymore. Instead, the Twig_Environment class has two new options: cache and auto_reload. Upgrading your code means changing this kind of code:

$loader = new Twig_Loader_Filesystem('/path/to/templates', '/path/to/compilation_cache', true);
$twig = new Twig_Environment($loader);

to something like this:

$loader = new Twig_Loader_Filesystem('/path/to/templates');
$twig = new Twig_Environment($loader, array(
  'cache' => '/path/to/compilation_cache',
  'auto_reload' => true,
));

The complete changelog follows:

  • made cache and auto_reload options of Twig_Environment instead of arguments of Twig_Loader
  • deprecated the “items” filter as it is not needed anymore
  • optimized template loading speed
  • removed output when an error occurs in a template and render() is used
  • made major speed improvements for loops (up to 300% on even the smallest loops)
  • added properties as part of the sandbox mode
  • added public properties support (obj.item can now be the item property on the obj object)
  • extended set tag to support expression as value ({% set foo as ‘foo’ ~ ‘bar’ %} )
  • fixed bug when \ was used in HTML

Twig 0.9.2 released

I have just released Twig 0.9.2. Lots of great changes occurred for this release:

  • made some speed optimizations
  • changed the cache extension to .php
  • added a js escaping strategy
  • added support for short block tag
  • changed the filter tag to allow chained filters
  • made lexer more flexible as you can now change the default delimiters
  • added set tag
  • changed default directory permission when cache dir does not exist (more secure)
  • added macro support
  • changed filters first optional argument to be a Twig_Environment instance instead of a Twig_Template instance
  • made Twig_Autoloader::autoload() a static method
  • avoid writing template file if an error occurs
  • added $ escaping when outputting raw strings
  • enhanced some error messages to ease debugging
  • fixed empty cache files when the template contains an error

Twig at the 2009 Zend Conference

Yesterday, I gave a talk about Twig at the Zend unconference. The slides are available at slideshare.

Twig 0.9.1 released

I have just released Twig 0.9.1. The changelog is pretty small, but a bug that prevented Twig to work on PHP 5.2.6 has been fixed:

  • fixed a bug in PHP 5.2.6
  • fixed numbers with one than one decimal
  • added support for method calls with arguments ({{ foo.bar('a', 43) }})
  • made small speed optimizations
  • made minor tweaks to allow better extensibility and flexibility

Twig has its own PEAR channel

Since the release of Twig as an Open-Source project with its own dedicated website, many people tried it and suggested me some enhancements. One of them was the possibility to install Twig with the PEAR command line.

That’s now possible. First, you need to register the Twig PEAR channel:

$ pear channel-discover pear.twig-project.org

Then, install Twig with the following command:

$ pear install twig/Twig-beta

Enjoy!

This website is powered by PHP and Twig.