可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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.
回答1:
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
回答2:
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' %}
.
回答3:
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
回答4:
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'); } ... }
回答5:
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')); } }