博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Symfony2CookBook:如何通过表单事件动态生成表单
阅读量:7101 次
发布时间:2019-06-28

本文共 5855 字,大约阅读时间需要 19 分钟。

  • 原文出处:
  • 原文作者:
  • 授权许可:
  • 翻译人员:FireHare
  • 校对人员:FireHare
  • 适用版本:Symfony 2.1
  • 文章状态:草译阶段

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

在直接进入动态表单生成之前,让我们先快速回顾一下常规的表单类,如下所示:

 
  1. // src/Acme/DemoBundle/Form/Type/ProductType.php 
  2. namespace Acme\DemoBundle\Form\Type; 
  3.  
  4. use Symfony\Component\Form\AbstractType; 
  5. use Symfony\Component\Form\FormBuilderInterface; 
  6.  
  7. class ProductType extends AbstractType 
  8.     public function buildForm(FormBuilderInterface $builderarray $options
  9.     { 
  10.         $builder->add('name'); 
  11.         $builder->add('price'); 
  12.     } 
  13.  
  14.     public function getName() 
  15.     { 
  16.         return 'product'
  17.     } 
If this particular section of code isn't already familiar to you, you probably need to take a step back and first review the before proceeding.
如果您不清楚上述这段代码段的话,您可能需要在继续之前先退一步看看

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(如从数据库是提取一个产品),该类所生成的表单看起来完全相同。

Suppose now, that you don't want the user to be able to change the name value once the object has been created. To do this, you can rely on Symfony's system to analyze the data on the object and modify the form based on the Product object's data. In this entry, you'll learn how to add this level of flexibility to your forms.

现在假定在对象创建之后你不希望用户可以修改name值。要做到这一点,您可以依赖Symfony的系统分析对象相关数据并修改基于Product对象数据的表单。在本文中,您将学到如何为您表单增添这种灵活性。

Adding An Event Subscriber To A Form Class
添加一个表单类的事件订阅

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"小部件,我们可以创建一个特殊的表单域,并委托它负责事件订阅:

 
  1. // src/Acme/DemoBundle/Form/Type/ProductType.php 
  2. namespace Acme\DemoBundle\Form\Type; 
  3.  
  4. use Symfony\Component\Form\AbstractType 
  5. use Symfony\Component\Form\FormBuilderInterface; 
  6. use Acme\DemoBundle\Form\EventListener\AddNameFieldSubscriber; 
  7.  
  8. class ProductType extends AbstractType 
  9.     public function buildForm(FormBuilderInterface $builderarray $options
  10.     { 
  11.         $subscriber = new AddNameFieldSubscriber($builder->getFormFactory()); 
  12.         $builder->addEventSubscriber($subscriber); 
  13.         $builder->add('price'); 
  14.     } 
  15.  
  16.     public function getName() 
  17.     { 
  18.         return 'product'
  19.     } 

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对象传递到它的构造函数中,这样一旦在表单创建期间有事件的调度通知,我们新的订阅器就能够创建表单小部件。

Inside the Event Subscriber Class
理解事件订阅类

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"表单域。有鉴于此,订阅器看起来如下所示:

 
  1. // src/Acme/DemoBundle/Form/EventListener/AddNameFieldSubscriber.php 
  2. namespace Acme\DemoBundle\Form\EventListener; 
  3.  
  4. use Symfony\Component\Form\Event\DataEvent; 
  5. use Symfony\Component\Form\FormFactoryInterface; 
  6. use Symfony\Component\EventDispatcher\EventSubscriberInterface; 
  7. use Symfony\Component\Form\FormEvents; 
  8.  
  9. class AddNameFieldSubscriber implements EventSubscriberInterface 
  10.     private $factory
  11.  
  12.     public function __construct(FormFactoryInterface $factory
  13.     { 
  14.         $this->factory = $factory
  15.     } 
  16.  
  17.     public static function getSubscribedEvents() 
  18.     { 
  19.         // Tells the dispatcher that we want to listen on the form.pre_set_data 
  20.         // event and that the preSetData method should be called. 
  21.         return array(FormEvents::PRE_SET_DATA => 'preSetData'); 
  22.     } 
  23.  
  24.     public function preSetData(DataEvent $event
  25.     { 
  26.         $data = $event->getData(); 
  27.         $form = $event->getForm(); 
  28.  
  29.         // During form creation setData() is called with null as an argument 
  30.         // by the FormBuilder constructor. We're only concerned with when 
  31.         // setData is called with an actual Entity object in it (whether new, 
  32.         // or fetched with Doctrine). This if statement let's us skip right 
  33.         // over the null condition. 
  34.         if (null === $data) { 
  35.             return
  36.         } 
  37.  
  38.         // check if the product object is "new" 
  39.         if (!$data->getId()) { 
  40.             $form->add($this->factory->createNamed('name''text')); 
  41.         } 
  42.     } 
It is easy to misunderstand the purpose of the if (null === $data) segment of this event subscriber. To fully understand its role, you might consider also taking a look at the and paying special attention to where setData() is called at the end of the constructor, as well as the setData() method itself.
在本事件订阅器中的if (null === $data)代码段的目的很容易引起误解。要完全认识它的作用,您也许需要考虑看看,并特别注意where setData() is called at the end of the constructor以及setData()函数本身。

The FormEvents::PRE_SET_DATA line actually resolves to the string form.pre_set_data. The serves an organizational purpose. It is a centralized location in which you can find all of the various form events available.

FormEvents::PRE_SET_DATA行实际上被解析成字符串form.pre_set_data。起到了一个组织的作用,它是一个集中的位置,在这里您可以找到所有可用的各种表单事件。

While this example could have used the form.set_data event or even the form.post_set_data events just as effectively, by using form.pre_set_data we guarantee that the data being retrieved from the Event object has in no way been modified by any other subscribers or listeners. This is because form.pre_set_data passes a object instead of the object passed by the form.set_data event. , unlike its child , lacks a setData() method.

虽然在这个例子中使用form.set_data事件甚至是form.post_set_data事件也同样有效,但使用form.pre_set_data,我们可以保证来自Event对象的数据没有被其它任何订阅器或监听器修改。这是因为form.pre_set_data发送一个 对象用以取代通过form.set_data事件发送的对象。不象其子对象,它少一个setData()方法。

You may view the full list of form events via the , found in the form bundle.
您可以通过来查看完整的表单事件列表,该类可以在form bundle中找到。

 

转载地址:http://clzhl.baihongyu.com/

你可能感兴趣的文章
Python之路【第二篇】:Python简介、解释器与编码
查看>>
Boxing
查看>>
一起学Android之GridView
查看>>
HBase笔记5(诊断)
查看>>
poj2092
查看>>
简单几何(极角排序) POJ 2007 Scrambled Polygon
查看>>
轻院1064加密字符
查看>>
ajx 发送json串(Request Payload格式)
查看>>
工资管理系统可行性分析人员分工
查看>>
BZOJ3781:小B的询问——题解
查看>>
BZOJ4557:[JLOI2016/SHOI2016]侦察守卫——题解
查看>>
通过Ajax和SpringBoot交互的示例
查看>>
可重入函数与不可重入函数
查看>>
[转] 深入剖析 linux GCC 4.4 的 STL string
查看>>
常用Web Service汇总(天气预报、时刻表等)
查看>>
resin app server安装总结
查看>>
抓取新浪新闻列表实例
查看>>
[04-06]鼠标悬停图片时,实现抖动效果
查看>>
抽象类和接口的区别
查看>>
react 自定义 TabBar 组件
查看>>