Using Twig with Zend Framework


Twig, in short, is a templating system for PHP. But PHP is already a templating system many would argue! Well, I wouldn’t argue against that point. However, with the recent excitement in the air in the PHP Community about Symfony 2, I thought it worth checking out.
Mostly I thought they were silly things that were not really needed unless you had a team of designers to work with, however, during my exploration, a couple of things occurred to me that I had not considered about templating systems before. One being the enforced separation of concerns they provide; you simply cannot do anything from inside them which you shouldn’t be, keeping your presentation very very clean. The second, being that they’re not all as terrible as Smarty.

Installing Twig

This really couldn’t get a lot simpler with pear:

    $ pear channel-discover pear.twig-project.org
    $ pear install twig/Twig

or, you can use the Git or Subversion repos as detailed on the projects website: http://www.twig-project.org/doc/intro.html

The Application Resource

Setting up a ZF application resource for twig is a snip! The minimal config required to set up a Twig instance, is exactly that, minimal!

Simple create the class “Core_Resource_Twig” and place it in library/Core/Resource/Twig.php and consider the following code:

<?php

class Core_Resource_Twig extends Zend_Application_Resource_ResourceAbstract
{
    /**
     * @var Twig_Environment
     */
    protected $twig;

    public function init()
    {
        $options = $this->getOptions();
        $loader = new Twig_Loader_Filesystem($options['templateDir']);
        $this->twig = new Twig_Environment(
                $loader,
                $options['options']
        );
        return $this->twig;
    }
}

All we are doing here, is creating an instance of the Filesystem Twig loader, which loads templates from files, and then passing that in to the Twig Environment, along with the rest of the options from our config, which in brief, would now look something like this:

[production]
autoloaderNamespaces[] = "Twig_"
pluginPaths.Core_Resource = APPLICATION_PATH "/../library/Core/Resource"

; FRONT CONTROLLER
resources.frontController.moduleDirectory = APPLICATION_PATH "/modules"
resources.frontController.controllerDirectory.default = APPLICATION_PATH "/controllers"
resources.frontController.noViewRenderer = true

; TWIG
resources.twig.templateDir = APPLICATION_PATH "/templates"
resources.twig.options.cache = APPLICATION_PATH "/../cache/twig"

[development : production]
resources.twig.options.debug = true
resources.twig.options.auto_reload = true

That now gives us two things, a configured Twig instance, and an application resource to hold it, which will be present in the invoke args in your controller. so for the next step, we stitch it together, and make it more useable, to make things super simple, a base controller class is useful here. The reason for a base controller class rather than an action helper is simple, performance, and simplicity; no need for the complexity or auto-rendering anything, we will simply call a method at the end of each action.

Given that we are now using twig, this has two benefits, we avoid the overhead of how ZF looks up the view name to decide which view template to render, which is a part of the bottleneck of ZF, and additionally, it matches more closely to the other documentation you’ll find on Twig elsewhere, and we are doing things in a slightly different manner to how we would use Zend_View, so why try to emulate it, when we are using something very different!

<?php

abstract class Core_Controller extends Zend_Controller_Action
{
    public function twig($template, array $vars)
    {
        $twig = $this->getBootstrap()->getResource('twig');

        $template = $twig->loadTemplate($template);
        $this->getResponse()->appendBody(
            $template->render($vars),
            'default'
        );
    }
}

Rendering the template

Now that we have our base controller class, we can now use our template, in this manner from our action:

<?php

class IndexController extends Core_Controller
{
    /**
     * @var Core_Service_Posts
     */
    protected $service;

    public function init()
    {
        $this->service = new Core_Service_Posts();
    }

    public function indexAction()
    {
        $recent = $this->service->recentPosts();
        $this->twig('home.twig', array(
            'recent' => $recent,
        ));
    }

    public function viewAction()
    {
        $id = $this->getRequest()->getParam('id', false);
        if (false === $id) {
            throw new Core_InvalidIdException('No ID Present');
        }

        $paste = $this->service->byId($id);

        $this->twig('view-post.twig', array(
            'post' => $paste,
        ));
    }

}

In this example, you have the indexAction, taking the service for the posts for the application, and passing the recent posts to the template, and in the view action, taking the selected post, and passes it to the template, with the selection of template for the action being passed as the first argument to our twig method we added to the base controller class.

And now, you can find examples and documentation on how to put together your twig templates here http://www.twig-project.org/documentation.

, , , ,

  1. #1 by [email protected] on May 5, 2011 - 4:45 am

    Very helpful post, especially the creation of the resource application resource and the related config.

    The two things that have stopped me from diving into Twig – despite lots of positive buzz from Twitter folks whom I follow and respect – are:

    1. How to handle/emulate ZF layouts in Twig.
    2. How to handle/emulate ZF view helpers in Twig.

    Any thoughts – or perhaps a follow-up post – on these issues?

    Again, many thanks for a clear and helpful post. ;-)

  2. #2 by Hari K T on May 5, 2011 - 3:32 pm

    Typo abstract class Core_Controller and IndexController is extending Core_SiteController .
    Also are you moving all the views scripts to templates folder ?
    If you have all the code some where in github ie also good :) .
    Thanks for the post .

  3. #3 by Jeremy on May 27, 2011 - 5:53 am

    I have to agree with David. Until Twig can work with ZF’s layout it’s not very useful to me.

  4. #4 by Ryan on May 27, 2011 - 9:19 am

    @ Jeremy
    Sorry for not following up on David’s reply here, he did have his question answered on twitter already..
    Twig does not have a solution the same as Zend_Layout, it instead has template inheritance, so there is no need for Zend_Layout with twig, it can not only perform the same job, it does it better!

    @Hari K T
    Thanks, fixed!

    @David
    Not only does twig have an equivalent to Layouts which is actually superior, it also has a solution which matches view helpers, in its extensions. They are a different methodology to view helpers, but they perform essentially the same task, and ultimately enforce the same strict policy of only presentation logic in the template itself when you use them, which is an added bonus.

  5. #5 by Adam H on July 1, 2011 - 3:27 am

    https://github.com/benjamindulau/Ano_ZFTwig

    I found this to be useful. Near seamless usage with Zend_Layout and Zend_View.

  6. #6 by admin on January 27, 2012 - 9:44 am

    Thanks for your comment, but when you make it look like seo spam, it ruins the sincerity of it.

Comments are closed.