天天看點

Symfony2CookBook:如何通過表單事件動态生成表單

Before jumping right into dynamic form generation, let's have a quick review of what a bare form class looks like:

在直接進入動态表單生成之前,讓我們先快速回顧一下正常的表單類,如下所示:

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

namespace Acme\DemoBundle\Form\Type; 

use Symfony\Component\Form\AbstractType; 

use Symfony\Component\Form\FormBuilderInterface; 

class ProductType extends AbstractType 

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

    { 

        $builder->add('name'); 

        $builder->add('price'); 

    } 

    public function getName() 

        return 'product'; 

Let's assume for a moment that this form utilizes an imaginary "Product" class that has only two relevant properties ("name" and "price"). The form generated from this class will look the exact same regardless of a new Product is being created or if an existing product is being edited (e.g. a product fetched from the database).

現在讓我們假定該表單使用一個虛拟的“Product”類,該類僅有兩個相關屬性("name"和"price")。無論是建立一個新的Product,還是編輯一個已存在的Product(如從資料庫是提取一個産品),該類所生成的表單看起來完全相同。

So, instead of directly adding that "name" widget via our ProductType form class, let's delegate the responsibility of creating that particular field to an Event Subscriber:

是以,替代直接通過我們的ProductType表單類添加"name"小部件,我們可以建立一個特殊的表單域,并委托它負責事件訂閱:

use Symfony\Component\Form\AbstractType 

use Acme\DemoBundle\Form\EventListener\AddNameFieldSubscriber; 

        $subscriber = new AddNameFieldSubscriber($builder->getFormFactory()); 

        $builder->addEventSubscriber($subscriber); 

The event subscriber is passed the FormFactory object in its constructor so that our new subscriber is capable of creating the form widget once it is notified of the dispatched event during form creation.

事件訂閱器将FormFactory對象傳遞到它的構造函數中,這樣一旦在表單建立期間有事件的排程通知,我們新的訂閱器就能夠建立表單小部件。

The goal is to create a "name" field only if the underlying Product object is new (e.g. hasn't been persisted to the database). Based on that, the subscriber might look like the following:

我們的目标是隻有在Product是建立對象(如:尚未持久化到資料庫)時,才建立一個"name"表單域。有鑒于此,訂閱器看起來如下所示:

// src/Acme/DemoBundle/Form/EventListener/AddNameFieldSubscriber.php 

namespace Acme\DemoBundle\Form\EventListener; 

use Symfony\Component\Form\Event\DataEvent; 

use Symfony\Component\Form\FormFactoryInterface; 

use Symfony\Component\EventDispatcher\EventSubscriberInterface; 

use Symfony\Component\Form\FormEvents; 

class AddNameFieldSubscriber implements EventSubscriberInterface 

    private $factory; 

    public function __construct(FormFactoryInterface $factory) 

        $this->factory = $factory; 

    public static function getSubscribedEvents() 

        // Tells the dispatcher that we want to listen on the form.pre_set_data 

        // event and that the preSetData method should be called. 

        return array(FormEvents::PRE_SET_DATA => 'preSetData'); 

    public function preSetData(DataEvent $event) 

        $data = $event->getData(); 

        $form = $event->getForm(); 

        // During form creation setData() is called with null as an argument 

        // by the FormBuilder constructor. We're only concerned with when 

        // setData is called with an actual Entity object in it (whether new, 

        // or fetched with Doctrine). This if statement let's us skip right 

        // over the null condition. 

        if (null === $data) { 

            return; 

        } 

        // check if the product object is "new" 

        if (!$data->getId()) { 

            $form->add($this->factory->createNamed('name', 'text')); 

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