跳到内容

如何自定义表单渲染

编辑此页

Symfony 为您提供了几种自定义表单渲染方式。在本文中,您将学习如何对表单的一个或多个字段进行单项自定义。如果您需要以相同的方式自定义所有表单,请创建一个表单主题或使用任何内置主题,例如 Symfony 表单的 Bootstrap 主题

表单渲染函数

只需调用一次 form() Twig 函数,即可渲染整个表单,包括所有字段和错误消息

1
2
3
4
{# form is a variable passed from the controller via
  $this->render('...', ['form' => $form])
  or $this->render('...', ['form' => $form->createView()]) #}
{{ form(form) }}

下一步是使用 form_start()form_end()form_errors()form_row() Twig 函数渲染不同的表单部分,以便您可以自定义它们,添加 HTML 元素和属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{{ form_start(form) }}
    <div class="my-custom-class-for-errors">
        {{ form_errors(form) }}
    </div>

    <div class="row">
        <div class="col">
            {{ form_row(form.task) }}
        </div>
        <div class="col" id="some-custom-id">
            {{ form_row(form.dueDate) }}
        </div>
    </div>
{{ form_end(form) }}

form_row() 函数输出整个字段内容,包括标签、帮助消息、HTML 元素和错误消息。所有这些都可以使用其他 Twig 函数进一步自定义,如下图所示

form_label()form_widget()(HTML 输入)、form_help()form_errors() Twig 函数使您可以完全控制每个表单字段的渲染方式,因此您可以完全自定义它们

1
2
3
4
5
6
7
8
9
10
<div class="form-control">
    <i class="fa fa-calendar"></i> {{ form_label(form.dueDate) }}
    {{ form_widget(form.dueDate) }}

    <small>{{ form_help(form.dueDate) }}</small>

    <div class="form-error">
        {{ form_errors(form.dueDate) }}
    </div>
</div>

警告

如果您正在手动渲染每个字段,请确保不要忘记自动添加的 _token 字段,以实现 CSRF 保护。

您还可以使用 {{ form_rest(form) }}(推荐)来渲染任何未手动渲染的字段。有关更多信息,请参阅下文的 form_rest() 文档

注意

本文稍后部分,您可以找到这些 Twig 函数的完整参考以及更多用法示例。

表单字段助手

上一节中显示的 form_*() 助手渲染表单字段的不同部分,包括其所有 HTML 元素。一些开发人员和设计师对这种行为感到困惑,因为它将所有 HTML 元素隐藏在表单主题中,而表单主题的自定义并非易事。

这就是 Symfony 提供其他 Twig 表单助手的原因,这些助手渲染每个表单字段部分的值,而不添加任何 HTML 包装

  • field_name()
  • field_value()
  • field_label()
  • field_help()
  • field_errors()
  • field_choices()(选择字段的迭代器;例如,用于 <select>

使用这些助手时,您必须为所有表单字段编写所有 HTML 内容,因此您不再需要处理表单主题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<input
    name="{{ field_name(form.username) }}"
    value="{{ field_value(form.username) }}"
    placeholder="{{ field_label(form.username) }}"
    class="form-control"
>

<select name="{{ field_name(form.country) }}" class="form-control">
    <option value="">{{ field_label(form.country) }}</option>

    {% for label, value in field_choices(form.country) %}
        <option value="{{ value }}">{{ label }}</option>
    {% endfor %}
</select>

表单渲染变量

上一节中提到的一些 Twig 函数允许传递变量来配置其行为。例如,form_label() 函数允许您定义自定义标签以覆盖表单中定义的标签

1
{{ form_label(form.task, 'My Custom Task Label') }}

某些 表单字段类型 具有可以传递给小部件的其他渲染选项。这些选项在每种类型中都有文档记录,但一个常见的选项是 attr,它允许您修改表单元素上的 HTML 属性。以下代码会将 task_field CSS 类添加到渲染的输入文本字段中

1
{{ form_widget(form.task, {'attr': {'class': 'task_field'}}) }}

注意

如果您一次渲染整个表单(或整个嵌入式表单),则 variables 参数将仅应用于表单本身,而不应用于其子表单。换句话说,以下代码不会将 "foo" 类属性传递给表单中的所有子字段

1
2
{# does **not** work - the variables are not recursive #}
{{ form_widget(form, { 'attr': {'class': 'foo'} }) }}

如果您需要“手动”渲染表单字段,则可以使用其 vars 属性访问字段的各个值(例如 idnamelabel)。例如,要获取 id

1
{{ form.task.vars.id }}

注意

本文稍后部分,您可以找到这些 Twig 变量的完整参考及其描述。

表单主题

前面几节中显示的 Twig 函数和变量可以帮助您自定义表单的一个或多个字段。但是,此自定义无法应用于应用程序的其余表单。

如果您想以相同的方式自定义所有表单(例如,使生成的 HTML 代码适应应用程序中使用的 CSS 框架),则必须创建表单主题

表单函数和变量参考

函数

form(form_view, variables)

渲染完整表单的 HTML。

1
2
{# render the form and change the submission method #}
{{ form(form, {'method': 'GET'}) }}

您通常会在原型设计或使用自定义表单主题时使用此助手。如果您需要在渲染表单时具有更高的灵活性,则应使用其他助手来渲染表单的各个部分

1
2
3
4
5
6
7
8
{{ form_start(form) }}
    {{ form_errors(form) }}

    {{ form_row(form.name) }}
    {{ form_row(form.dueDate) }}

    {{ form_row(form.submit, { 'label': 'Submit me' }) }}
{{ form_end(form) }}

form_start(form_view, variables)

渲染表单的开始标记。此助手负责打印表单的配置方法和目标操作。如果表单包含上传字段,它还将包含正确的 enctype 属性。

1
2
{# render the start tag and change the submission method #}
{{ form_start(form, {'method': 'GET'}) }}

form_end(form_view, variables)

渲染表单的结束标记。

1
{{ form_end(form) }}

除非您将 render_rest 设置为 false,否则此助手还会输出 form_rest()(本文稍后会对此进行解释)

1
2
{# don't render unrendered fields #}
{{ form_end(form, {render_rest: false}) }}

form_label(form_view, label, variables)

渲染给定字段的标签。您可以选择传递要作为第二个参数显示的特定标签。

1
2
3
4
5
6
7
8
9
{{ form_label(form.name) }}

{# The two following syntaxes are equivalent #}
{{ form_label(form.name, 'Your Name', {'label_attr': {'class': 'foo'}}) }}

{{ form_label(form.name, null, {
    'label': 'Your name',
    'label_attr': {'class': 'foo'}
}) }}

请参阅“如何自定义表单渲染”以了解有关 variables 参数的信息。

form_help(form_view)

渲染给定字段的帮助文本。

1
{{ form_help(form.name) }}

form_errors(form_view)

渲染给定字段的任何错误。

1
2
3
4
5
{# render only the error messages related to this field #}
{{ form_errors(form.name) }}

{# render any "global" errors not associated to any form field #}
{{ form_errors(form) }}

警告

在 Bootstrap 4 表单主题中,form_errors() 已包含在 form_label() 中。有关详细信息,请阅读 Bootstrap 4 主题文档

form_widget(form_view, variables)

渲染给定字段的 HTML 小部件。如果您将其应用于整个表单或字段集合,则将渲染每个基础表单行。

1
2
{# render a widget, but add a "foo" class to it #}
{{ form_widget(form.name, {'attr': {'class': 'foo'}}) }}

form_widget() 的第二个参数是变量数组。最常见的变量是 attr,它是应用于 HTML 小部件的 HTML 属性数组。在某些情况下,某些类型还具有可以传递的其他与模板相关的选项。这些将在类型的基础上进行讨论。如果您一次渲染多个字段(例如 form_widget(form)),则 attributes 不会递归地应用于子字段。

请参阅“如何自定义表单渲染”以了解有关 variables 参数的更多信息。

form_row(form_view, variables)

渲染给定字段的“行”,它是字段的标签、错误、帮助和部件的组合。

1
2
{# render a field row, but display a label with text "foo" #}
{{ form_row(form.name, {'label': 'foo'}) }}

form_row() 的第二个参数是变量数组。Symfony 中提供的模板仅允许覆盖标签,如上面的示例所示。

请参阅“如何自定义表单渲染”以了解有关 variables 参数的信息。

form_rest(form_view, variables)

这会渲染给定表单中尚未渲染的所有字段。最好始终在表单中的某个位置包含此内容,因为它会为您渲染隐藏字段,并使您更容易发现忘记渲染的任何字段(因为它会为您渲染该字段)。

1
{{ form_rest(form) }}

form_parent(form_view)

如果表单视图已经是根表单,则返回父表单视图或 null。应优先使用此函数来访问父表单,而不是使用 form.parent 访问父表单。当子表单命名为 parent 时,后一种方法会产生不同的结果。

测试

可以通过在 Twig 中使用 is 运算符来创建条件来执行测试。有关更多信息,请阅读 Twig 文档

selectedchoice(selected_value)

此测试将检查当前选择是否等于 selected_value,或者当前选择是否在数组中(当 selected_value 是数组时)。

1
<option {% if choice is selectedchoice(value) %}selected="selected"{% endif %}>

rootform

此测试将检查当前 form 是否没有父表单视图。

1
2
3
4
5
6
7
8
9
10
11
12
{# DON'T DO THIS: this simple check can't differentiate between a form having
    a parent form view and a form defining a nested form field called 'parent' #}

 {% if form.parent is null %}
     {{ form_errors(form) }}
 {% endif %}

{# DO THIS: this check is always reliable, even if the form defines a field called 'parent' #}

 {% if form is rootform %}
     {{ form_errors(form) }}
 {% endif %}

表单变量参考

以下变量是每种字段类型通用的。某些字段类型可能定义更多变量,并且此处的一些变量实际上仅适用于某些类型。要了解每种类型可用的确切变量,请查看您的表单主题使用的模板代码。

假设您的模板中有一个 form 变量,并且您想引用 name 字段上的变量,则可以通过使用 FormView 对象上的公共 vars 属性来访问变量

1
2
3
4
<label for="{{ form.name.vars.id }}"
    class="{{ form.name.vars.required ? 'required' }}">
    {{ form.name.vars.label }}
</label>
变量 用法
action 当前表单的操作。
attr 将作为字段的 HTML 属性渲染的键值数组。
block_prefixes 父类型的所有名称的数组。
cache_key 用于缓存的唯一键。
compound 字段是否实际上是子字段组的持有者(例如,choice 字段,它实际上是一组复选框)。
data 类型的规范化数据。
disabled 如果 true,则将 disabled="disabled" 添加到字段。
errors 附加到特定字段的任何错误的数组(例如,form.title.errors)。请注意,您不能使用 form.errors 来确定表单是否有效,因为这仅返回“全局”错误:某些单个字段可能存在错误。而是使用 valid 选项。
form 当前的 FormView 实例。
full_name 要渲染的 name HTML 属性。
help 将要渲染的帮助消息。
id 要渲染的 id HTML 属性。
label 将要渲染的字符串标签。
label_attr 将作为标签的 HTML 属性渲染的键值数组。
method 当前表单的方法 (POST, GET 等)。
multipart 如果 true,则 form_enctype 将渲染 enctype="multipart/form-data"
name 字段的名称(例如 title) - 但不是 name HTML 属性,它是 full_name
required 如果 true,则将 required 属性添加到字段以激活 HTML5 验证。此外,还会将 required 类添加到标签。
submitted 根据整个表单是否已提交,返回 truefalse
translation_domain 此表单的翻译域。
valid 根据整个表单是否有效,返回 truefalse
value 渲染时将使用的值(通常是 value HTML 属性)。这仅适用于根表单元素。

提示

在幕后,当 Form 组件在表单树的每个“节点”上调用 buildView()finishView() 时,这些变量会提供给表单的 FormView 对象。要查看特定字段具有哪些“视图”变量,请查找表单字段(及其父字段)的源代码,并查看上述两个函数。

这项工作,包括代码示例,已根据 Creative Commons BY-SA 3.0 许可获得许可。
目录
    版本