什么';这是为应用程序后端和前端全局设置两种不同形式主题的最方便方法


What's the most convenient way to globally set 2 different form themes for app back-end and front-end

因此,在Symfony2中对表单进行主题化很容易。您创建了一个自定义主题文件,并将其添加到config.yml文件中进行加载。完成。

然而,我有两个不同的形式主题。一个用于应用程序的前端,一个用于该应用程序的后端。

我查阅了文件(http://symfony.com/doc/2.3/cookbook/form/form_customization.html)但是找不到一个简单的方法。

当我将主题添加到config.yml文件时,我在前端和后端都有相同的主题。我也可以在每个视图中包括表格,比如这个

{% form_theme form 'form_table_layout.html.twig' %}

然而,这意味着我必须在每个视图中都这样做。

有没有办法为前端和后端创建一个单独的配置文件?我可以在基础模板文件中指出应该使用哪个表单主题吗?

我还能做什么吗?

如果使用Symfony2默认目录结构,即前端和后端都有一个内核,则只能(如前所述)在每个模板中设置表单主题,或者通过在config.yml文件中设置来在应用程序范围内使用相同的模板。

您提到的另一种解决方案,即创建两个基本模板,每个模板设置一个"全局"form_theme标记,理论上是可行的。使用以下标签为所有前端页面创建一个基本front-end.html.twig模板:

{% form_theme form 'form-front-end.html.twig' %}

这是可行的,但您将被迫在每个继承的模板中都有一个form变量。您也无法将主题设置为同一页面中的多个表单。

您可以通过检查表单变量是否在设置其样式之前定义来改进解决方案:

{% if form is defined %}
  {% form_theme form 'form-front-end.html.twig' %}
{% endif %}

或者更好的是,如果你想将多个表单传递到同一个模板,你可以使用forms数组:

{% if forms is defined %}
  {% for form in forms %}
    {% form_theme form 'form-front-end.html.twig' %}
  {% endfor %}
{% endif %}

好的是,即使您根本不传递变量,这也不会引发任何异常,但您必须记住将任何要呈现的表单放入forms数组中。

显然,您会对后端基本模板执行同样的操作。

也许有更好的解决方案,但与此同时,我希望这会有所帮助!

我以前也遇到过这个问题,找到了这篇文章,并按照Andrea Sprega的建议行事。最近我想出了一个办法,可以省去一些重复的打字。

警告:这有点"黑客",可能不是最好的方法,也不能保证在下一个框架版本中工作。当你阅读下面的内容时,你就会明白为什么。

目标:我们希望根据应用程序的"环境"(最常见的例子是"前端"answers"后端")拥有不同的默认表单模板。但从根本上讲,Symfony并不知道这样的"环境".虽然可以将项目拆分到不同的环境中并加载不同的配置,但如果我们想要的只是具有不同的表单模板,那么这绝对是一种过度的做法。

我认为最好的方法是在基本模板中设置/覆盖默认表单主题。因此,我们可以在前端基础模板中设置表单主题A,在后端基础模板中创建表单主题B。对我来说,这听起来是最好的解决方案,因为表单主题是一种"视图"的东西,所以在视图中更改它是非常有意义的。然而,问题似乎是,当执行trick(模板)代码时,表单视图已经初始化。因此,现在更改默认的表单主题已经太晚了。(我可能错了,因为我没有深入挖掘到100%的信心)

所以我决定换一种方式。它是这样工作的:

  • 首先,我假设所有前端控制器都将扩展相同的基类(例如"BaseFrontendController")。类似地,所有后端控制器都将扩展相同的BaseBackendController类。以下是我们如何区分前端和后端环境。事实上,在我的项目中就是这样
  • 默认的分支模板将添加到这些基本控制器类中。它可以通过一个方法或一个注释来完成。在这篇文章中,我将使用一种公共方法
  • 在执行控制器之前,覆盖已定义的默认分支模板
  • 初始化表单视图时,它将使用控制器中定义的默认分支模板

以下是操作方法:

首先,在config.yml中定义的默认表单主题将传递给'Symfony'Component'Form'AbstractRendererEngine的构造函数,并分配给本地实例$defaultThemes。该字段受到保护,以便其派生类可以使用,但没有设置程序来更改其值。

因此,我们需要推出自己的Symfony'Bridge'Twig'Form'TwigRendererEngine:

namespace AppBundle'Form'Twig;
use Symfony'Bridge'Twig'Form'TwigRendererEngine as BaseTwigRendererEngine;
class TwigRendererEngine extends BaseTwigRendererEngine
{
    /**
     * @param array $defaultThemes
     */
    public function addDefaultThemes($defaultThemes)
    {
        $this->defaultThemes = array_merge($this->defaultThemes, $defaultThemes);
    }
}

这个自定义渲染器引擎非常简单——它只添加了一个新方法,将默认主题附加到现有主题上。这就是为什么我说它是"黑客"——当内部发生变化时,它将不再工作。

其次,定义一个接口TwigTemplateProvider,它将由基本的前端/后端控制器类实现:

namespace AppBundle'Form'Twig;
interface TwigTemplateProvider
{
    /**
     * @return array|string The form template path
     */
    public function getDefaultFormTwigTemplates();
}

第三,我们需要一个监听器,它将在控制器执行时运行。

<?php
namespace AppBundle'EventListener;
use AppBundle'Form'Twig'TwigRendererEngine;
use AppBundle'Form'Twig'TwigTemplateProvider;
use Symfony'Component'HttpKernel'Event'FilterControllerEvent;
class PerControllerFormTemplateListener
{
    /**
     * @var 'Twig_Environment
     */
    private $twig;
    public function __construct('Twig_Environment $twig)
    {
        $this->twig = $twig;
    }
    public function onKernelController(FilterControllerEvent $event)
    {
        $controller = $event->getController();
        if (!is_array($controller)) {
            return;
        }
        if ($controller[0] instanceof TwigTemplateProvider) {
            /** @var 'Symfony'Bridge'Twig'Extension'FormExtension $formExtension */
            $formExtension = $this->twig->getExtension('form');
            $engine = $formExtension->renderer->getEngine();
            if ($engine instanceof TwigRendererEngine) {
                $templates = (array)$controller[0]->getDefaultFormTwigTemplates();
                $engine->addDefaultThemes($templates);
            }
        }
    }
}

监听器将获得由实现TwigTemplateProvider接口的控制器提供的表单模板名称(以字符串或数组形式)。然后它会将其添加到默认主题列表中,并将其传递给表单渲染器引擎。

现在,通过在services.yml中添加以下内容将它们连接在一起:

parameters:
    twig.form.engine.class: AppBundle'Form'Twig'TwigRendererEngine
services:
    app.form.per_controller_template_listener:
        class: AppBundle'EventListener'PerControllerFormTemplateListener
        arguments: ["@twig"]
        tags:
            - { name: kernel.event_listener, event: kernel.controller, method: onKernelController }

在这里,我们将%twig.form.engine.class%参数设置为自己的实现,并将事件侦听器添加到堆栈中。

使用它非常简单。例如,在基本前端控制器中,实现TwigTemplateProvider并添加以下方法:

public function getDefaultFormTwigTemplates()
{
    return 'frontend/form_layout.html.twig';
}

然后,当执行前端控制器时,此布局将被添加到表单模板堆栈中。