Symfony 添加默认模板搜索路径 [英] Symfony add default template search path

查看:28
本文介绍了Symfony 添加默认模板搜索路径的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的问题类似于 这个问题 但略有不同,因为那个问题没有回答,我想我会再试一次.

My question is similar to this question but slightly different and since that question wasn't answered, I thought I would try again.

我知道 Symfony 会首先在 app/Resources/FooBundle/views 中查找模板,然后在 FooBundle/Resources/views 中查找模板.我想在两者之间注入"另一个位置,例如

I know Symfony will look first in app/Resources/FooBundle/views and then second in FooBundle/Resources/views for templates. I would like to "inject" another location between the two, e.g.

  1. app/Resources/FooBundle/views
  2. BarBundle/Resources/FooBundle/views
  3. FooBundle/资源/视图

我尝试覆盖 \Symfony\Component\HttpKernel\Config\FileLocator 服务并在那里添加了一个路径,但这没有用.我也在控制器中尝试了答案here方法没有成功.(建议的本机"方法不起作用,因为路径来自动态设置.)

I've tried overriding the \Symfony\Component\HttpKernel\Config\FileLocator service and added a path there, but this didn't work. I've also tried the answer here in the controller::render method without success. (the 'native' method suggested there doesn't work because the path comes from a dynamic setting.)

作为次要说明,我需要能够稍后(可能是 onRequest)而不是在创建容器时添加此路径.因此,控制器中的 EventListener、自定义服务方法或调用将是合适的.

As a secondary note, I need to be able to add this path later (maybe onRequest) instead of at container creation. So an EventListener, custom service method or call in the controller would be appropriate.

推荐答案

解决这个问题的部分挑战是意识到(至少在 Symfony 2.7 中)至少有两种方法可以指定模板名称:'oldway'(因为没有更好的名字)和后来实现的'name-spaced'方法.例如

Part of the challenge in solving this problem was realizing that (at least in Symfony 2.7) there are at least two ways to specify a template name: the 'old way' (for lack of a better name) and the 'name-spaced' method which was implemented later. e.g.

class MyController extends \Symfony\Bundle\FrameworkBundle\Controller\Controller
{
    // the 'old way'
    public function barAction()
    {
        return $this->render('FooBundle:User:foo.html.twig');
    }
    // namespaced
    public function fooAction()
    {
        return $this->render('@Foo/User/foo.html.twig');
    }
}

这两种方法会导致不同的模板位置搜索,因此必须在两个不同的地方修改代码.

These two methods result in different template location searches and therefore code had to be modified in two different places.

为了修改'旧'方式,我覆盖了 Kernel::locateResource() 方法

In order to modify the 'old' way, I overrode the Kernel::locateResource() method

public function locateResource($name, $dir = null, $first = true)
{
    $customBundle = $this->container->get('my_custom_bundle');
    $locations = parent::locateResource($name, $dir, false);
    if ($locations && (false !== strpos($locations[0], $dir))) {
        // if found in $dir (typically app/Resources) return it immediately.
        return $locations[0];
    }

    // add custom path to template locator
    // this method functions if the controller uses `@Template` or `FooBundle:Foo:index.html.twig` naming scheme
    if ($customBundle && (false === strpos($name, $customBundle->getName()))) {
        // do not add override path to files from same bundle
        $customPath = $customBundle->getPath() . '/Resources';
        return parent::locateResource($name, $customPath, true);
    }
    return $locations[0];
}

为了修改namespace的方式,我加了一个ControllerListener

In order to modify the namespace way, I added a ControllerListener

class OverrideListener implements EventSubscriberInterface
{
    private $loader;
    private $customBundle;

    function __construct(\Twig_Loader_Filesystem $loader, $customBundle)
    {
        $this->loader = $loader;
        $this->customBundle = $customBundle;
    }

    /**
     * @param FilterControllerEvent $event
     * @throws \Twig_Error_Loader
     */
    public function setUpOverrides(FilterControllerEvent $event)
    {
        // add custom path to template locator
        // This 'twig.loader' functions only when @Bundle/template (name-spaced) name-scheme is used
        $controller = $event->getController()[0];
        if ($controller instanceof AbstractController) {
            $bundleName = $controller->getName(); // my AbstractController adds a getName method returning the BundleName
            if ($this->customBundle) {
                $overridePath = $this->customBundle->getPath() . '/Resources/' . $bundleName . '/views';
                if (is_readable($overridePath)) {
                    $paths = $this->loader->getPaths($bundleName);
                    // inject overridePath before the original path in the array
                    array_splice($paths, count($paths) - 1, 0, array($overridePath));
                    $this->loader->setPaths($paths, $bundleName);
                }
            }
        }
    }

    public static function getSubscribedEvents()
    {
        return array(
            KernelEvents::CONTROLLER => array(array('setUpOverrides')),
        );
    }
}

我希望这可以帮助任何寻求类似解决方案的人.

I hope this helps anyone coming along looking for a similar solution.

这篇关于Symfony 添加默认模板搜索路径的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆