天天看點

Symfony2CookBook:如何建立自定義的表單域類型

Symfony comes with a bunch of core field types available for building forms. However there are situations where we want to create a custom form field type for a specific purpose. This recipe assumes we need a field definition that holds a person's gender, based on the existing choice field. This section explains how the field is defined, how we can customize its layout and finally, how we can register it for use in our application.

Symfony自帶了一組用于建構表單的核心表單域類型。但在有些情況下,我們為了某個目的需要建立自定義表單域類型。本文假定我們需要基于現有的choice表單域定義一個表單域,用來儲存使用者性别。本文将闡述如何定義表單域、如何設定它的布局及最終顯示、如何在應用程式中注冊以便使用。

// src/Acme/DemoBundle/Form/Type/GenderType.php 

namespace Acme\DemoBundle\Form\Type; 

use Symfony\Component\Form\AbstractType; 

use Symfony\Component\OptionsResolver\OptionsResolverInterface; 

class GenderType extends AbstractType 

    public function setDefaultOptions(OptionsResolverInterface $resolver) 

    { 

        $resolver->setDefaults(array( 

            'choices' => array( 

                'm' => 'Male', 

                'f' => 'Female', 

            ) 

        )); 

    } 

    public function getParent() 

        return 'choice'; 

    public function getName() 

        return 'gender'; 

The location of this file is not important - the Form\Type directory is just a convention.

該檔案的位置并不重要,放在Form\Type目錄隻是根據慣例。

buildForm() - Each field type has a buildForm method, which is where you configure and build any field(s). Notice that this is the same method you use to setup your forms, and it works the same here.

buildForm() - 每個域類型都有一個buildForm方法,在該方法中您可以配置和建構任何表單域。注意這與您設定您表單的方法相同,同時它們的工作原理也相同。

If you're creating a field that consists of many fields, then be sure to set your "parent" type as form or something that extends form. Also, if you need to modify the "view" of any of your child types from your parent type, use the finishView() method.

如果您正在建立一個由許多表單域組成的表單域,然後您的“父”類型設為表單或者設為表單的擴充。此外,如果您需要修改您父類型下任何子類型的“視圖”,請使用finishView()方法。

The getName() method returns an identifier which should be unique in your application. This is used in various places, such as when customizing how your form type will be rendered.

getName()方法傳回一個在您應用程式中唯一的辨別。它将被用于不同的地方,如定制您的表單類型要如何渲染。

The goal of our field was to extend the choice type to enable selection of a gender. This is achieved by fixing the choices to a list of possible genders.

我們表單域的目的是要擴充choice類型,以便能選擇性别。這裡通過固定的性别選擇清單來實作。

In this case, since our parent field is choice, we don't need to do any work as our custom field type will automatically be rendered like a choice type. But for the sake of this example, let's suppose that when our field is "expanded" (i.e. radio buttons or checkboxes, instead of a select field), we want to always render it in a ul element. In your form theme template (see above link for details), create a gender_widget block to handle this:

在本例中,因為我們的父表單域是choice,是以我們不需要做任何工作,作為我們自定義的域類型會自動按choice類型模闆渲染。但就在這個例子裡,讓我們假定我們的表單域是“擴大”的(如用單選按鈕或複選框來代替select表單域),我們想總是在ul元素中渲染它。那麼在您表單主題模闆中(詳情參見上面的連結),讓我們建立一個gender_widget區塊來處理上述假定:

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

{% block gender_widget %} 

    {% spaceless %} 

        {% if expanded %} 

            <ul {{ block('widget_container_attributes') }}> 

            {% for child in form %} 

                <li> 

                    {{ form_widget(child) }} 

                    {{ form_label(child) }} 

                </li> 

            {% endfor %} 

            </ul> 

        {% else %} 

            {# just let the choice widget render the select tag #} 

            {{ block('choice_widget') }} 

        {% endif %} 

    {% endspaceless %} 

{% endblock %} 

Make sure the correct widget prefix is used. In this example the name should be gender_widget, according to the value returned by getName. Further, the main config file should point to the custom form template so that it's used when rendering all forms.

確定使用正确的小部件字首。在這個例子中,根據getName傳回的值,小部件的名稱應該是gender_widget。此外,當自定義表單模闆被用于渲染所有表單時,在主配置檔案中應該指向該模闆。

# app/config/config.yml 

twig: 

    form: 

        resources: 

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

You can now use your custom field type immediately, simply by creating a new instance of the type in one of your forms:

您現在可以馬上使用您的自定義域類型,隻需要簡單地在您表單中建立一個該類型的新執行個體:

// src/Acme/DemoBundle/Form/Type/AuthorType.php 

use Symfony\Component\Form\FormBuilderInterface; 

class AuthorType extends AbstractType 

    public function buildForm(FormBuilderInterface $builder, array $options) 

        $builder->add('gender_code', new GenderType(), array( 

            'empty_value' => 'Choose a gender', 

But this only works because the GenderType() is very simple. What if the gender codes were stored in configuration or in a database? The next section explains how more complex field types solve this problem.

但這僅僅隻是可以工作,因為GenderType()非常簡單。如果gender相關代碼是被儲存在配置檔案或資料庫中呢?下一節将闡述更複雜的域類型将如何解決該問題。

So far, this entry has assumed that you have a very simple custom field type. But if you need access to configuration, a database connection, or some other service, then you'll want to register your custom type as a service. For example, suppose that we're storing the gender parameters in configuration:

到目前為止,本文隻是假定您有一個非常簡單的自定義域類型。但如果您需要通路配置、資料庫連接配接或其它服務,您需要将您自定義的類型注冊成服務。舉個例子,假設我們在配置中儲存了gender的參數:

parameters: 

    genders: 

        m: Male 

        f: Female 

To use the parameter, we'll define our custom field type as a service, injecting the genders parameter value as the first argument to its to-be-created __construct function:

要使用該參數,我們需要将我們自定義的域類型定義成服務,并将genders參數值做為它的構造函數__construct的第一個參數注入:

# src/Acme/DemoBundle/Resources/config/services.yml 

services: 

    form.type.gender: 

        class: Acme\DemoBundle\Form\Type\GenderType 

        arguments: 

            - "%genders%" 

        tags: 

            - { name: form.type, alias: gender } 

Be sure that the alias attribute of the tag corresponds with the value returned by the getName method defined earlier. We'll see the importance of this in a moment when we use the custom field type. But first, add a __construct argument to GenderType, which receives the gender configuration:

務必讓tag的alias屬性與前面定義的getName方法的傳回值一緻。當我們使用自定義表單域類型時這非常重要。但首先,請添加GenderType的__construct參數,用以接受gender的配置參數值:

// ... 

    private $genderChoices; 

    public function __construct(array $genderChoices) 

        $this->genderChoices = $genderChoices; 

            'choices' => $this->genderChoices, 

    // ... 

Great! The GenderType is now fueled by the configuration parameters and registered as a service. And because we used the form.type alias in its configuration, using the field is now much easier:

太棒了!GenderType現在可以通過配置參數生效,并被注冊成服務。因為我們在它的配置中使用了form.type别名,現在使用表單域更容易了:

        $builder->add('gender_code', 'gender', array( 

Notice that instead of instantiating a new instance, we can just refer to it by the alias used in our service configuration, gender. Have fun!

注意,與執行個體化一個新的執行個體不同,我們隻需要通過在我們的服務配置中使用别名gender,就可以引用它。玩得開心!

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