天天看點

Symfony2CookBook:如何進行表單的定制渲染

Symfony gives you a wide variety of ways to customize how a form is rendered. In this guide, you'll learn how to customize every possible part of your form with as little effort as possible whether you use Twig or PHP as your templating engine.

Symfony為您提供了各式各樣的方式來定制表單渲染,在本指南中,無論您使用的是Twig還是PHP模闆引擎,您都将花極少的精力就可以學到如何定制您表單中的每個部分。

Recall that the label, error and HTML widget of a form field can easily be rendered by using the form_row Twig function or the row PHP helper method:

回想一下,表單域的标簽(label)、錯誤(error)以及HTML小部件都能夠很友善地通過Twig的form_row方法或PHP的row助手方法來進行渲染。

{{ form_row(form.age) }} 

You can also render each of the three parts of the field individually:

您也可以單獨渲染該表單域三部分中的每一部分:

<div> 

    {{ form_label(form.age) }} 

    {{ form_errors(form.age) }} 

    {{ form_widget(form.age) }} 

</div> 

In both cases, the form label, errors and HTML widget are rendered by using a set of markup that ships standard with Symfony. For example, both of the above templates would render:

在上述兩個示例中,表單标簽(label)、錯誤(error)和HTML小部件是通過使用一系列Symfony的标準标簽來進行渲染的。比如上述兩個模闆都将渲染成:

    <label for="form_age">Age</label> 

    <ul> 

        <li>This field is required</li> 

    </ul> 

    <input type="number" id="form_age" name="form[age]" /> 

To quickly prototype and test a form, you can render the entire form with just one line:

為了對表單進行快速原型設計和測試,您可以僅用一行代碼來渲染整個表單:

{{ form_widget(form) }} 

Symfony uses form fragments - a small piece of a template that renders just one part of a form - to render every part of a form - - field labels, errors, input text fields, select tags, etc

Symfony利用表單片段(一小段僅對表單一部分進行渲染的模闆)來渲染表單的每個部分。如:标簽(label)、錯誤(error)、輸入文本框(input)和選擇(select)辨別等。

The fragments are defined as blocks in Twig and as template files in PHP.  

表單片段在在Twig引擎中被稱為區塊,在PHP引擎中被稱為模闆檔案。

A theme is nothing more than a set of fragments that you want to use when rendering a form. In other words, if you want to customize one portion of how a form is rendered, you'll import a theme which contains a customization of the appropriate form fragments.

主題無非是您想用來渲染表單的一組表單片段。換句話說,如果您想定制部分表單的渲染方式,您應該導入一個主題,其中包含了定制的表單片斷。

Symfony自帶一個預設的主題(Twig引擎的預設主題是form_div_layout.html.twig檔案,而在PHP引擎的預設主題則位于是FrameworkBundle:Form名稱空間中),其中定義了渲染表單各部分時需要用到的所有表單片段。

In the next section you will learn how to customize a theme by overriding some or all of its fragments.

下一節,您将學到如何通過重寫主題的部分或全部片斷來定制該主題。

For example, when the widget of a integer type field is rendered, an input number field is generated

例如,當一個整數型表單域小部件被渲染時,将生成一個數字類型的輸入框。

{{ form_widget(form.age) }} 

renders:

渲染結果:

<input type="number" id="form_age" name="form[age]" required="required" value="33" /> 

Internally, Symfony uses the integer_widget fragment to render the field. This is because the field type is integer and you're rendering its widget (as opposed to its label or errors).

在内部,symfony采用integer_widget片斷來渲染該表單域。這是因為該表單域的類型是整型,且您正在渲染它的小部件(相對于label或errror來說)。

In PHP it would rather be the integer_widget.html.php file located in FrameworkBundle/Resources/views/Form folder.

PHP引擎則是從FrameworkBundle/Resources/views/Form檔案夾中取出integer_widget.html.php檔案

The default implementation of the integer_widget fragment looks like this:

integer_widget片段的預設實作如下所示:

{# integer_widget.html.twig #} 

{% block integer_widget %} 

    {% set type=type|default('number') %} 

    {{ block('field_widget') }} 

{% endblock integer_widget %} 

As you can see, this fragment itself renders another fragment - field_widget:

如您所見,該片斷本身是由另一個片斷(field_widget)來渲染:

(譯者:field_widget将被form_widget所替代,目前保留還保留field_widget區塊,将于2.3版時删除)

{# FrameworkBundle/Resources/views/Form/field_widget.html.twig #} 

{% block field_widget %} 

    {% set type=type|default('text') %} 

    <input type="{{ type }}" {{ block('widget_attributes') }} value="{{ value }}" /> 

{% endblock field_widget %} 

The point is, the fragments dictate the HTML output of each part of a form. To customize the form output, you just need to identify and override the correct fragment. A set of these form fragment customizations is known as a form "theme". When rendering a form, you can choose which form theme(s) you want to apply.

可以看出,這些片段決定了表單各部分的HTML輸出。要對表單輸出進行定制,您隻需要定義并覆寫正确的片斷即可。這樣一組定制的表單片斷就被稱為表單“主題”。這樣當渲染表單時,您就可以選擇您想應用的表單主題了。

In Twig a theme is a single template file and the fragments are the blocks defined in this file.

對于Twig引擎而言,一個主題就是單個的模闆檔案,同時表單片斷對應該檔案中的區塊。

In PHP a theme is a folder and the fragments are individual template files in this folder.

而對于PHP引擎而方,一個主題則是一個檔案夾,同時每個表單片斷則對應于該檔案夾中的單個模闆檔案。

Knowing which block to customize

了解要定制的區塊

In this example, the customized fragment name is integer_widget because you want to override the HTML widget for all integer field types. If you need to customize textarea fields, you would customize textarea_widget.

在這個例子中,要定制的片斷是integer_widget,這是因為您想覆寫HTML小部件中所有的integer域類型。如果您要定制textarea域,那麼您需要定制textarea_widegt。

As you can see, the fragment name is a combination of the field type and which part of the field is being rendered (e.g. widget, label, errors, row). As such, to customize how errors are rendered for just input text fields, you should customize the text_errors fragment.

如您所見,片斷名是由域類型和要渲染的表單域(如:widget、label、errors等)組合而成的。是以,如果您要為text域定制渲染錯誤的方法,那麼您應該定制text_errors片斷。

More commonly, however, you'll want to customize how errors are displayed across all fields. You can do this by customizing the field_errors fragment. This takes advantage of field type inheritance. Specifically, since the text type extends from the field type, the form component will first look for the type-specific fragment (e.g. text_errors) before falling back to its parent fragment name if it doesn't exist (e.g. field_errors).

然而,更常見的是,你想定制在所有表單域中渲染錯誤的方法,您可以通過field_errors片段來實作。這需要利用域類型的繼承。具體而言,因為所有的text類型都是自field類型擴充而來,form元件首先查找特殊類型的片斷(如text_errors),如果該片斷不存在,則查找該片斷的父片段(如field_errors)。

To see the power of form theming, suppose you want to wrap every input number field with a div tag. The key to doing this is to customize the integer_widget fragment.

為了展現表單主題的強大,讓我們假定您想把所有的number表單域放到div标簽裡。要做到這一點,對integer_widget片斷進行定制是關鍵。

When customizing the form field block in Twig, you have two options on where the customized form block can live:

在Twig引擎中定制form域區塊時,對于将定制的表單區塊放置何處,您有兩種選擇:

Method 放置方式

Pros 優點

Cons 缺點

Inside the same template as the form

放置在目前模闆中

Quick and easy

簡單快速

Can't be reused in other templates

不能被其它模闆重用

Inside a separate template

放置在獨立模闆中

Can be reused by many templates

可以被多個模闆重用

Requires an extra template to be created

需要建立一個額外模闆

Both methods have the same effect but are better in different situations.

這兩種放置方式的效果是相同的,分别适用于不同的情形。

The easiest way to customize the integer_widget block is to customize it directly in the template that's actually rendering the form.

定制integer_widget區塊最簡單的方法是直接在實際渲染表單的模闆中定制。

{% extends '::base.html.twig' %} 

{% form_theme form _self %} 

    <div class="integer_widget"> 

        {% set type=type|default('number') %} 

        {{ block('field_widget') }} 

    </div> 

{% endblock %} 

{% block content %} 

    {# ... render the form #} 

    {{ form_row(form.age) }} 

 By using the special {% form_theme form _self %} tag, Twig looks inside the same template for any overridden form blocks. Assuming the form.age field is an integer type field, when its widget is rendered, the customized integer_widget block will be used.

通過使用特殊的{% form_theme form _self %}标簽,Twig引擎可以在目前模闆中覆寫任意的表單區塊。假定form.age域是一個整數類型的表單域,當它的小部件被渲染時,将使用定制的integer_widget區塊。

The disadvantage of this method is that the customized form block can't be reused when rendering other forms in other templates. In other words, this method is most useful when making form customizations that are specific to a single form in your application. If you want to reuse a form customization across several (or all) forms in your application, read on to the next section.

這種方式的弊端是該定制表單區域不能在其它模闆中渲染其它表單時重用。換句話說,這種方式在您應用程式中對特定的單個表單進行定制時最為有用。如果您想在您應用程式的部分或全部表單重複使用一個表單定制的話,那麼請繼續閱讀下一節。

You can also choose to put the customized integer_widget form block in a separate template entirely. The code and end-result are the same, but you can now re-use the form customization across many templates:

您也可以選擇将定制的integer_widget表單區塊放在一個完全獨立的模闆中,代碼和最終結果是一樣的,但現在您可以在許多模闆中重用這個表單定制了。

{# src/Acme/DemoBundle/Resources/views/Form/fields.html.twig #} 

Now that you've created the customized form block, you need to tell Symfony to use it. Inside the template where you're actually rendering your form, tell Symfony to use the template via the form_theme tag:

現在您已經定制了表單區塊,您需要告訴Symfony使用它。在實際渲染您表單的模闆中,可以通過form_theme标簽來告訴Symfony使用它:

{% form_theme form 'AcmeDemoBundle:Form:fields.html.twig' %} 

When the form.age widget is rendered, Symfony will use the integer_widget block from the new template and the input tag will be wrapped in the div element specified in the customized block.

當form.age小元件被渲染,Symfony将從新模闆中使用integer_widget區塊,input标簽将被包含定制區塊指定的div元素中。

When using PHP as a templating engine, the only method to customize a fragment is to create a new template file - this is similar to the second method used by Twig.

The template file must be named after the fragment. You must create a integer_widget.html.php file in order to customize the integer_widget fragment.

<!-- src/Acme/DemoBundle/Resources/views/Form/integer_widget.html.php --> 

<div class="integer_widget"> 

    <?php echo $view['form']->renderBlock('field_widget', array('type' => isset($type) ? $type : "number")) ?> 

Now that you've created the customized form template, you need to tell Symfony to use it. Inside the template where you're actually rendering your form, tell Symfony to use the theme via the setTheme helper method:

<?php $view['form']->setTheme($form, array('AcmeDemoBundle:Form')) ;?> 

<?php $view['form']->widget($form['age']) ?> 

When the form.age widget is rendered, Symfony will use the customized integer_widget.html.php template and the input tag will be wrapped in the div element.

This is easy to do, but varies slightly depending on if your form block customizations are in the same template as the form or a separate template.

這很容易做到,但略有不同,這取決于您是在目前模闆還是在獨立模闆中定制表單區塊。

Import the blocks by adding a use tag in the template where you're rendering the form:

您可以通過在渲染表單的模闆中添加use标簽來導入區塊:

{% use 'form_div_layout.html.twig' with integer_widget as base_integer_widget %} 

現在,當區塊從form_div_layout.html.twig模闆中導入時,integer_widget區塊被稱為base_integer_widget。這意味着在您重定義integer_widget區塊時,您可以通過base_integer_widget來引用預設标記:

        {{ block('base_integer_widget') }} 

If your form customizations live inside an external template, you can reference the base block by using the parent() Twig function:

如果您在外部模闆中進行表單定制,那麼您可以使用Twig引擎的parent()函數來引用基本區塊:

{% extends 'form_div_layout.html.twig' %} 

        {{ parent() }} 

It is not possible to reference the base block when using PHP as the templating engine. You have to manually copy the content from the base block to your new template file.

在使用PHP模闆引擎時,是無法引入基本區塊的。您不得不要将基本區塊的内容通過手工方式複制到您新的模闆檔案中。

If you'd like a certain form customization to be global to your application, you can accomplish this by making the form customizations in an external template and then importing it inside your application configuration:

如果您想要在您應用程式範圍中使用某個表單定制,您可以将其寫入一個外部模闆,并在您應用程式配置中導入。

By using the following configuration, any customized form blocks inside the AcmeDemoBundle:Form:fields.html.twig template will be used globally when a form is rendered.

通過使用以下配置,任何在AcmeDemoBundle:Form:fields.html.twig模闆中定制的表單區塊在全局範圍内都将在表單渲染時使用。

# app/config/config.yml 

twig: 

    form: 

        resources: 

            - 'AcmeDemoBundle:Form:fields.html.twig' 

    # ... 

By default, Twig uses a div layout when rendering forms. Some people, however, may prefer to render forms in a table layout. Use the form_table_layout.html.twig resource to use such a layout:

一般來說,Twig引擎在渲染表單時使用div标簽布局。然而對有些人來說,他們更喜歡使用table标簽布局的方式來渲染表單,這需要使用form_table_layout.html.twig資源。

        resources: ['form_table_layout.html.twig'] 

If you only want to make the change in one template, add the following line to your template file rather than adding the template as a resource:

如果您隻想應用到一個模闆中,那麼在您的模闆檔案中添加以下語句,而無須将該模闆作為資源添加:

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

Note that the form variable in the above code is the form view variable that you passed to your template.

注意,在以上代碼中的表單變量是由您傳遞到模闆中的表單視圖變量。

By using the following configuration, any customized form fragments inside the src/Acme/DemoBundle/Resources/views/Form folder will be used globally when a form is rendered.

framework: 

    templating: 

        form: 

            resources: 

                - 'AcmeDemoBundle:Form' 

By default, the PHP engine uses a div layout when rendering forms. Some people, however, may prefer to render forms in a table layout. Use the FrameworkBundle:FormTable resource to use such a layout:

                - 'FrameworkBundle:FormTable' 

<?php $view['form']->setTheme($form, array('FrameworkBundle:FormTable')); ?> 

Note that the $form variable in the above code is the form view variable that you passed to your template.

So far, you've seen the different ways you can customize the widget output of all text field types. You can also customize individual fields. For example, suppose you have two text fields - first_name and last_name - but you only want to customize one of the fields. This can be accomplished by customizing a fragment whose name is a combination of the field id attribute and which part of the field is being customized. For example:

到目前為止,您所看到的都是定制整個text域類型小部件輸出的不同方法,您也可以定制單個表單域。例如,假設您有兩個text域(first_name和last_name),但您隻想定制其中的一個,這可以通過定制一個片斷(片斷名由表單域的id和被定制的表單域部分組成)來實作。如下所示:

{% block _product_name_widget %} 

    <div class="text_widget"> 

{{ form_widget(form.name) }} 

Here, the _product_name_widget fragment defines the template to use for the field whose id is product_name (and name is product[name]).

在這裡,_product_name_widget片斷定義了用于id是product_name表單域的模闆。

The product portion of the field is the form name, which may be set manually or generated automatically based on your form type name (e.g. ProductType equates to product). If you're not sure what your form name is, just view the source of your generated form.

表單域的product部分是表單名,它可以是手工設定或基于您的表單類型名自動生成的(如:ProductType對應product)。如果您不确定您的表單名,您可以檢視一個您所生成表單的源代碼即可。

You can also override the markup for an entire field row using the same method:

您也可以采用相同的方式來覆寫整個表單域行的辨別:

{# _product_name_row.html.twig #} 

{% block _product_name_row %} 

    <div class="name_row"> 

        {{ form_label(form) }} 

        {{ form_errors(form) }} 

        {{ form_widget(form) }} 

There are many different ways to customize how errors are rendered when a form is submitted with errors. The error messages for a field are rendered when you use the form_errors helper:

當出錯表單被送出時,有很多方法來定制錯誤如何渲染。當您使用form_error助手函數時,表單域的錯誤資訊将被渲染。

{{ form_errors(form.age) }} 

By default, the errors are rendered inside an unordered list:

一般情況下,錯誤将被渲染在一個無序清單:

<ul> 

    <li>This field is required</li> 

</ul> 

To override how errors are rendered for all fields, simply copy, paste and customize the field_errors fragment.

要覆寫所有表單域的錯誤渲染,隻需要簡單地複制、粘貼并定制field_errers片斷即可。

{# fields_errors.html.twig #} 

{% block field_errors %} 

    {% spaceless %} 

        {% if errors|length > 0 %} 

        <ul class="error_list"> 

            {% for error in errors %} 

                <li>{{ error.messageTemplate|trans(error.messageParameters, 'validators') }}</li> 

            {% endfor %} 

        </ul> 

        {% endif %} 

    {% endspaceless %} 

{% endblock field_errors %} 

You can also customize the error output for just one specific field type. For example, certain errors that are more global to your form (i.e. not specific to just one field) are rendered separately, usually at the top of your form:

您也可以為某些特定域類型定制錯誤輸出。舉個例子,将某些針對您表單全局的錯誤(而非特定某個表單域的錯誤)單獨渲染,通常出現在您表單的頂部:

{{ form_errors(form) }} 

To customize only the markup used for these errors, follow the same directions as above, but now call the block form_errors (Twig) / the file form_errors.html.php (PHP). Now, when errors for the form type are rendered, your customized fragment will be used instead of the default field_errors.

要定制僅用于這些錯誤的辨別,請遵循上述說明,但現在被稱為form_errors區塊(Twig)/form_errors檔案(PHP)。現在,當表單類型的錯誤被渲染時,您的定制片斷将被使用,用于代替預設的field_errors。

When you can manage it, the easiest way to render a form field is via the form_row function, which renders the label, errors and HTML widget of a field. To customize the markup used for rendering all form field rows, override the field_row fragment. For example, suppose you want to add a class to the div element around each row:

當您要管理它時,最簡單的方式就是通過form_row函數來渲染表單域,該函數渲染一個表單域的标簽(label)、錯誤(errors)和HTML小部件(widget)。要定制用于渲染所有表單域行的辨別,請覆寫field_row片斷。舉個例子,假定您想要添加一個類讓div元素包含每個表單域行:

{# field_row.html.twig #} 

{% block field_row %} 

    <div class="form_row"> 

{% endblock field_row %} 

If you want to denote all of your required fields with a required asterisk (*), you can do this by customizing the field_label fragment.

如果您想要通過一個必需星号(*)标示您所有的必需表單域,您可以通過定制field_label片斷來實作。

In Twig, if you're making the form customization inside the same template as your form, modify the use tag and add the following:

使用Twig引擎,如果您在目前模闆中實作表單定制的話,那麼使用use标簽并添加下列語句:

{% use 'form_div_layout.html.twig' with field_label as base_field_label %} 

{% block field_label %} 

    {{ block('base_field_label') }} 

    {% if required %} 

        <span class="required" title="This field is required">*</span> 

    {% endif %} 

In Twig, if you're making the form customization inside a separate template, use the following:

使用Twig引擎,如果您是在獨立模闆中實作表單定制的話,那麼使用下列語句:

    {{ parent() }} 

When using PHP as a templating engine you have to copy the content from the original template:

當使用PHP作為模闆引擎時,您不得不從原始模闆中複制内容:

<!-- field_label.html.php --> 

<!-- original content --> 

<label for="<?php echo $view->escape($id) ?>" <?php foreach($attr as $k => $v) { printf('%s="%s" ', $view->escape($k), $view->escape($v)); } ?>><?php echo $view->escape($view['translator']->trans($label)) ?></label> 

<!-- customization --> 

<?php if ($required) : ?> 

    <span class="required" title="This field is required">*</span> 

<?php endif ?> 

You can also customize your form widgets to have an optional "help" message. In Twig, If you're making the form customization inside the same template as your form, modify the use tag and add the following:

您也可以定制您的表單小部件,使之具有一個可選的“幫助”資訊。在Twig模闆中,如果您在目前模闆中實作表單定制的話,那麼使用use标簽并添加下列語句:

{% use 'form_div_layout.html.twig' with field_widget as base_field_widget %} 

    {{ block('base_field_widget') }} 

    {% if help is defined %} 

        <span class="help">{{ help }}</span> 

In twig, If you're making the form customization inside a separate template, use the following:

<!-- field_widget.html.php --> 

<!-- Original content --> 

<input 

    type="<?php echo isset($type) ? $view->escape($type) : "text" ?>" 

    value="<?php echo $view->escape($value) ?>" 

    <?php echo $view['form']->renderBlock('attributes') ?> 

/> 

<!-- Customization --> 

<?php if (isset($help)) : ?> 

    <span class="help"><?php echo $view->escape($help) ?></span> 

To render a help message below a field, pass in a help variable:

要在表單域後渲染幫助資訊,需要發送help變量:

{{ form_widget(form.title, {'help': 'foobar'}) }} 

本文轉自 firehare 51CTO部落格,原文連結:http://blog.51cto.com/firehare/999962,如需轉載請自行聯系原作者