Android,iOS,Gadgets,Reviews Everything About Technology

Using a String as a Twig Template in Symfony2

120

I switched my preferred method to use the Twig_Loader_Chain class . This method allows you to assign multiple loaders to one Twig_Environment instance, so that you can transparently process templates from files or from strings. At the bottom of the article you will see a description of this method.

In order to create a twig template, you need an instance of the Twig_Environment class . This class contains a method render , which returns the processed result from a twig template (usually from a file). Twig Environment uses a class loader that implements the Twig_LoaderInterface interface , this class loads data from the repository (file, database) for later analysis by the template engine. By default, Symfony2 uses the Twig_Loader_Filesystemclass , which loads template data from files, in order to create a template from a string, we need an instance of Twig_Environment, which uses the Twig_Loader_String class to retrieve data. There are several ways how you can do this, the easiest way is to create an instance of Twig_Environment and as a bootloader, give it an instance of the Twig_Loader_String class (this code can be placed inside your controller):

<?php

$twig = new \Twig_Environment(new \Twig_Loader_String());
$rendered = $twig->render(
    "Test string template: {{ result }}",
    array("result" => "Success!")
);

This works great as a quick solution, but the problem here is that in the template you will not have access to Symfony services or user services, this is because we created a fresh instance of Twig_Environment without any additional settings provided by Symfony. It’s better to take a copy of the existing Twig_Environment service used by Symfony itself and change it for use Twig_Loader_String(you can use it in your controller):

<?php

$twig = clone $this->get('twig');
$twig->setLoader(new \Twig_Loader_String());
$rendered = $twig->render(
    "Test string template: {{ result|humanize }}",
    array("result" => "mega_success")
);

Here I cloned the original Symfony service to make sure that Symfony can still process the template from the file. Another method is to create your own Twig service using Symfony’s dependency injection system. Here I added a custom twig service to my config.ymlproject:

services:
    mine.twig_string_loader:
        class: "Twig_Loader_String"
    mine.twig_string:
        class: "%twig.class%"
        arguments: [@mine.twig_string_loader, %twig.options% ]

Then you can use this service within your controller, like so:

<?php

$rendered = $this->get('mine.twig_string')->render(
    "Test string template: {{ result }}",
    array("result" => "Success!")
);

Unfortunately, this method has the same traps as in the first method, it will not include any Symfony Twig extensions or own extensions. Of course, these extensions can be added to this custom Twig service, but it’s much easier to just clone an existing Twig service and change it, if necessary. As mentioned above, using Twig Chain Loader is the preferred method, use it to assign multiple Symfony loaders to the main Twig instance. To use this method, you must use Symfony2.2 or later. Adding an additional bootloader to a Symfony Twig instance can be achieved by creating a new Twig_Loader_String bootloader, as follows:

twig.stringloader:
    class: Twig_Loader_String
    tags:
        - { name: twig.loader }

These settings should be added to the file config.ymlor configuration file of your bundle. An important part here is the tag twig.loader– it tells Symfony that you need to assign the Twig_Loader_String class as an additional loader in the main Twig instance. The beauty of this method is that Symfony will display templates from files and string patterns transparently without any additional effort. You can simply call the render method and pass a string or a link to the template file to it, and Twig will determine which loader to use for your template. Below is an example of this in action:

<?php

class DefaultController extends Controller
{
    public function indexAction()
    {
        $renderedString = $this->get('twig')->render('{{ name }}', array('name' => 'test'));
        $renderedTemplate = $this->get('twig')->render('MyBundle:Default:index.html.twig');
    }
}

Both calls will successfully process the templates. Twig service will determine which loader should be used based on the provided data.

Comments