Symfony2: Twig: Default template file in custom lo

2019-04-26 07:17发布

I try to load a simple base.html.twig template file that was moved from symfony's default location app/Resources/views/ to the custom location theme/.

The template file contains:

    <!DOCTYPE html>
    <html>
     <head>
     ...
     </head>
     <body>
      {% block body %}{% endblock %}
     </body>
    </html>

Extending the above template file by the controller Acme\Core\CoreBundle\Controller by using the controller-specific template

    {% extends '::base.html.twig' %}
    {% block body %}
      Hello world!
    {% endblock %}

leads to an error saying Unable to find template "::base.html.twig" in "AcmeCoreCoreBundle:Default:index.html.twig"..

How is it possible to tell symfony where to find the template files in global space?

Thanks in advance.

标签: php symfony twig
5条回答
SAY GOODBYE
2楼-- · 2019-04-26 07:20

I managed to find another solution to this which is much quicker to implement. I did try the accepted answer on this question first but was still having so path issues.

Just before my render call the template I added the path to the twig.loader container like this:

$this->container->get('twig.loader')->addPath('../../../../theme/', $namespace = '__main__');

Now twig templates will be rendered from a directory called 'theme' in the root folder. I found this solution from Fabien Pontencier himself (the creator of Symfony and Twig) on a reply to a twig bug here: https://github.com/symfony/symfony/issues/1912

查看更多
我欲成王,谁敢阻挡
3楼-- · 2019-04-26 07:21

From an action you can get the 'twig.loader'-service from the (service)-container:

$this->get('twig.loader')->addPath('path/to/your/directory');

And then you can use this path in your template.

@besta did it with a twig extension, injecting the twig loader into the constructor. But in twig extension you can use the environment:

class YourTwigExtension extends \Twig_Extension {
...
   public function initRuntime(\Twig_Environment $environment) {
      $this->environment = $environment;
      $this->environment->getLoader()->addPath(__DIR__ . '/Resources/views');
   }
...
}
查看更多
姐就是有狂的资本
4楼-- · 2019-04-26 07:24

There's a native feature to do exactly what you want in a nice way. Escentially you can add a twig namespace to the twig configuration in app/config.yml like this:

twig:
    # ...
    paths:
        "%kernel.root_dir%/../vendor/acme/foo-bar/templates": foo_bar

This creates an alias to the folder vendor/acme/foo-bar/templates and then you can use it to render your templates either from the controllers:

return $this->render(
    '@foo_bar/template.html.twig',
    $data
);

or from other twig templates

{% include '@foo_bar/template.html.twig' %}

Source: official cookbook http://symfony.com/doc/current/cookbook/templating/namespaced_paths.html

查看更多
混吃等死
5楼-- · 2019-04-26 07:46

Due to Adam's hint I am able to answer the question on my own. So I want to provide my answer if anybody is interested in.

The AcmeDemoBundle provides a twig extension (class Acme\DemoBundle\Twig\Extension\DemoExtension) that you simply can use. Change the constructor to

    public function __construct(FilesystemLoader $loader)
    {
     $this->loader = $loader;
     $this->loader->addPath('path/to/your/directory');
    }

Now tell symfony to register the twig extension. Edit your config.yml file (e.g. app/config/config.yml) and append

    services:
     demo.twig.extension
      class: Acme\DemoBundle\Twig\Extension\DemoExtension
      tags:
       - { name: twig.extension }
      arguments:
       - @Twig.loader

Last but not least change your extending twig file and remove the :: from your default template's namespace: {% extends 'base.html.twig' %}.

查看更多
Melony?
6楼-- · 2019-04-26 07:46

Assuming you want this done globally, this sort of stuff is meant to be done in a compiler pass.

It would be much cleaner and efficient like this:

<?php

use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;

class CustomCompilerPass implements CompilerPassInterface
{
    public function process(ContainerBuilder $container)
    {
        $loader = $container->getDefinition('twig.loader');
        $loader->addMethodCall('addPath', array('/path/to/views'));
    }
}
查看更多
登录 后发表回答