7
votes

I would like to load certain Twig templates from the database in my Symfony2 application, while still keeping the possibility to use the native loader to render templates in the standard filesystem locations. How to achieve this?

As far as I've understood, there is no possibility to register multiple loaders to Twig environment. I have been thinking two ways (for now):

  • Replace the default loader with a custom proxy class. When templates are referred with the standard @Bundle-notation, proxy would pass the request to the default loader. In other case, the request would be passed to my custom (database) loader; OR
  • Build up a completely new Twig environment. This method would require registering custom Twig extensions to both environments and it does not allow cross-referencing templates from different sources (some from @Bundles, some from database)

Update 1:

It seems that Twig supports Twig_Loader_Chain class that could be used in my first option. Still, the default loader should be accessible and passed to the chain as the first option.

2

2 Answers

6
votes

To use Twig_Loader_Chain you need Symfony 2.2 https://github.com/symfony/symfony/pull/6131
Then you can simply configurate your loaders:

services:
    twig.loader.filesystem:
        class: %twig.loader.filesystem.class%
        arguments:
            - @templating.locator
            - @templating.name_parser
        tags:
            - { name: twig.loader }
    twig.loader.string:
        class: %twig.loader.string.class%
        tags:
            - { name: twig.loader }

Update:
It looks like there are still some problems(the filesystem loader couldn't find the templates somtimes) but I found this:
http://forum.symfony-project.org/viewtopic.php?t=40382&p=131254

Seems to be working great!

2
votes

This is a cheap and cheerful way to temporarily change the loader in your standard env:

    // Keep the current loader
    $oldLoader = $env->getLoader();

    // Temporarily set a string loader   
    $env->setLoader(new \Twig_Loader_String());

    // Resolve the template - but don't render it yet.
    $template = $env->resolveTemplate($template);

    // Restore the old loader
    $env->setLoader($oldLoader);

    // Render the template. This will pass the old loader into any subtemplates and make sure your string based template gets into the cache.
    $result = $template->render($context);

I suppose this will work with other custom loaders.