> Symfony中文手册 > 如何使用表单主题

如何使用表单主题

表单输出的每一个部分都是可以进行自定义的。你可以随意地改变每一个表单“行”(form “row”)的渲染,改变用于输出错误的HTML标记,甚至自定义 textarea 标签应该如何输出。没有任何限制,不同的个性化设置可以用在不同的场合。

Symfony使用模板来渲染每一个或者部分的表单,比如label 标签,input 标签,错误信息以及任何其他内容。

在Twig中,每一个表单“片段”(fragment)是通过Twig block(模板代码区块)来渲染的。要自定义表单输出的任何一个部分,你只需要覆写相对应的block。

PHP模板中,每个表单“片段”是通过单独的模板文件来渲染的,要自定义表单输出的任何一个部分,你只需通过创建新模板来覆盖旧模板。

要理解了它们是如何工作的,自定义 form_row 片段并添加一个class属性到“包裹了每一个表单行”的 div 元素中。要实现这个,先创建一个新的模板文件,用于存放新的HTML标记:

1
2
3
4
5
6
7
8
9
10
{# app/Resources/views/form/fields.html.twig #}
{% block form_row %}
{% spaceless %}
    <div class="form_row">
        {{ form_label(form) }}
        {{ form_errors(form) }}
        {{ form_widget(form) }}
    </div>
{% endspaceless %}
{% endblock form_row %}
1
2
3
4
5
6
<!-- app/Resources/views/form/form_row.html.php -->
<div class="form_row">
    <?php echo $view['form']->label($form, $label) ?>
    <?php echo $view['form']->errors($form) ?>
    <?php echo $view['form']->widget($form, $parameters) ?>
</div>

form_row 表单片段,会在多数字段经由 form_row 函数被渲染出来时使用。要告诉表单组件去使用你的新 form_row 片段,把下面代码添加到输出表单的模板顶部:

1
2
3
4
5
6
7
{# app/Resources/views/default/new.html.twig #}
{% form_theme form 'form/fields.html.twig' %}
 
{# or if you wAnt to use multiple themes / 或者,如果你希望使用多个主题 #}
{% form_theme form 'form/fields.html.twig' 'form/fields2.html.twig' %}
 
{# ... render the form #}
1
2
3
4
5
6
7
<!-- app/Resources/views/default/new.html.php -->
<?php $view['form']->setTheme($form, array('form')) ?>
 
<!-- or if you want to use multiple themes -->
<?php $view['form']->setTheme($form, array('form', 'form2')) ?>
 
<!-- ... render the form -->

form_theme 标签(Twig中的)“导入”了定义在给定模板中的片段,并且在输出表单的时候使用它们。换句话说,当 form_row 模板函数在模板中被调用后,它将从你的自定义主题中(而不是Symfony自带的 form_row 区块)去使用form_row 块。

你的个性化主题不必覆写所有的表单区块。当渲染一个“你未在个性化主题中进行覆写”的区块儿时,表单主题引擎会回滚到全局主题(在bundle级别进行了定义)。

在拥有多个自定义主题的情况下,在回滚到全局主题之前,会按照罗列的顺序进行搜索(并使用)。

要自定义你的表单的任何一部分,只需覆写适当的片段。准确地知道哪些区块或文件将被覆写,是下一小节的课题。

更多信息请参考 如何自定义表单渲染。

表单片段的命名 ¶

在Symfony中,表单所输出的每一部分 - HTML表单元素,错误信息,表单标签,等等 - 都是被定义在基础主题里面,基础主题是一个Twig的block区块集合,在PHP模板中它是一组模板文件的集合。

在Twig中,每一个所需的区块儿都被定义在一个单独的模板文件中(form_div_layout.html.twig),它们被存放在 Twig Bridge 里面。在这个文件中,你可以看到渲染一个表单时所需要的每一个block和默认的每一个字段类型(field type)。

在PHP模板中,片段是单独的模板文件。 它们默认存放于FrameworkBundle的 Resources/views/Form 目录下 (参见 gitHub)。

每个片段的命名,都遵循同一基本原则,其名字被一个下划线(_)分割为两部分,下面是一些例子:

  • form_row - 被 form_row() 用来渲染大部分字段;

  • textarea_widget - 被 form_widget() 用来渲染一个 textarea 字段类型;

  • form_errors - 被 form_errors() 用来渲染某字段的错误信息。

每个片段都遵循同一基本的命名原则:type_parttype 部分对应被渲染的字段 类型 (如 textarea, checkbox, date 等),而 part 部分对应着是 什么 会被渲染(如label, widget, errors 等)。默认情况下,一个表单有4种可能的 parts 可以用来输出:

label (如 form_label()) 渲染字段的标签
widget (如 form_widget()) 渲染字段的html呈现
errors (如 form_errors()) 渲染错误信息
row (如 form_row()) 渲染字段一整行(包括label、widget、errors)

Note

另外确实还有其他2个 part 类型 - rowsrest - 不过你极少会有覆写这两个区块的需求。

通过知晓字段类型 (如 textarea) 和你想自定义哪一部分(如 widget),即可构建出需要覆写的片段之名称(如 textarea_widget)。

模板片段的继承 ¶

在某些情况下,你想要进行自定义的片段可能会不存在。比如,Symfony提供的默认主题中并没有 textarea_errors 片段。那么如何来渲染一个textarea字段的错误信息呢?

答案是:通过 form_errors 片段。Symfony在输出一个textarea类型的错误时,在回滚到 form_errors 片段之前,它先去查找一个textarea_errors片段。每个字段类型都有一个 parent type(父类型。textarea 的父类型是 text,其父级是 form),如果某个基础片段不存在,Symfony就会转而使用其父类型的片段。

所以,如果仅需覆写 textarea 字段的errors,拷贝 form_errors 片段,重命名为 textarea_errors 并对其自定义。要覆写 全体 字段类型的默认errors输出,应直接拷贝并定制 form_errors 片段。

Tip

对于每一种字段类型,form type reference/表单类型参考 中有每个字段类型的“parent”父类型。

全局的表单样式 ¶

在前面的例程中,我们使用了 form_theme helper(仅限Twig模板)来把自定义的表单片段,仅“导入”到当前表单。你也可以告诉Symfony横跨整个项目来导入自定义表单(类型)。

Twig ¶

为了能在 所有 的模板里,从之前创建的 fileds.html.twig 模板中自动包容自定义的区块儿,修改你的程序级配置文件:

1
2
3
4
5
# app/config/config.yml
twig:
    form_themes:
        - 'form/fields.html.twig'
    # ...
1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- app/config/config.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="Http://symfony.com/schema/dic/services"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:twig="http://symfony.com/schema/dic/twig"
    xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd
        http://symfony.com/schema/dic/twig http://symfony.com/schema/dic/twig/twig-1.0.xsd">
 
    <twig:config>
        <twig:theme>form/fields.html.twig</twig:theme>
        <!-- ... -->
    </twig:config>
</container>
1
2
3
4
5
6
7
// app/config/config.php
$container->loadFromExtension('twig', array(
    'form_themes' => array(
        'form/fields.html.twig',
    ),
    // ...
));

现在,fields.html.twig 模板中的任何一个block都可以被全局地用来定义表单输出了。

使用Twig在单一文件中自定义表单的全部输出

在Twig中,你也可以在“需要自定义的模板”中,自定义一个表单区块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{% extends 'base.html.twig' %}
 
{# import "_self" as the form theme #}
{# 导入 "_self" 作为表单主题 #}
{% form_theme form _self %}
 
{# make the form fragment customization #}
{# 实施表单片段的自定义 #}
{% block form_row %}
    {# custom field row output / “字段行”的定制输出 #}
{% endblock form_row %}
 
{% block content %}
    {# ... #}
 
    {{ form_row(form.task) }}
{% endblock %}

{% form_theme form _self %} 标签允许表单区块直接在“使用这些自定义表单的模版中”进行定制。在当前需要(个性化表单)的模版中使用此方法以便快速客制化表单输出。

Caution

{% form_theme form _self %} 功能, 在当前模板继承了其他模板时才能起作用。如果你的模板并未继承其他模板,则必须把 form_theme 指向一个单独模板。

PHP ¶

为了能在 所有 的模板里,从之前创建的 app/Resources/views/form 目录中自动包容自定义的模板,修改你的程序级配置文件:

1
2
3
4
5
6
7
# app/config/config.yml
framework:
    templating:
        form:
            resources:
                - 'form'
# ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!-- app/config/config.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:framework="http://symfony.com/schema/dic/symfony"
    xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd
        http://symfony.com/schema/dic/symfony http://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
 
    <framework:config>
        <framework:templating>
            <framework:form>
                <framework:resource>Form</framework:resource>
            </framework:form>
        </framework:templating>
        <!-- ... -->
    </framework:config>
</container>
1
2
3
4
5
6
7
8
9
10
11
// app/config/config.php
$container->loadFromExtension('framework', array(
    'templating' => array(
        'form' => array(
            'resources' => array(
                'Form',
            ),
        ),
    ),
    // ...
));

现在,任何一个位于 AppBundle/Resources/views/Form 目录中的模板片段,都可以全局地用于定义表单输出了。