【问题标题】:Symfony2: adding form fields dynamically using information from requestSymfony2:使用请求中的信息动态添加表单字段
【发布时间】:2013-02-12 13:49:13
【问题描述】:

场景:

  1. 第 1 步:从一些古老的 Web 服务中获取信息
  2. 第 2 步:在我的表单中添加 x 单选按钮,而 x 取决于来自网络服务的信息

我知道我应该添加一个事件订阅者类,如图所示in the documentation

$event 有一个 setData 方法。可能我必须使用它。如何从控制器访问此方法?

附加信息: 我正在使用教义。目前我正在创建一个 Doctrine 实体并将其传递给如下形式:

$product = new Product(); $form = $this->createForm(new ProductType(), $product);

【问题讨论】:

    标签: symfony symfony-forms


    【解决方案1】:

    这是我最终得到的解决方案。不确定这是否是最好的方法,所以这个答案没有被标记为正确,以鼓励其他更有经验的 Symfony 用户提出更好的解决方案。

    我不喜欢这个解决方案的一点是,我不能再将整个产品实体传递给表单,而是必须将每个属性单独添加到选项数组中:

    反正现在就是这样实现的:

    动态数据使用选项数组作为第二个参数传递给 createForm():

      // ExampleController.php
    
      use Acme\ExampleBundle\Entity\Product;
      public function addAction()
      {
         // choices contains the dynamic data I am fetching from the webservice in my actual code
         $choices = array("key1" => "value1", "key2" => "value2");
    
         // now create a new Entity
         $product = new Product();
    
         // and some attributes already have values for some reason
         $product->setPrice(42);
    
         $form = $this->createForm(new AddproductType(), 
                  array(
                     "choices" => $choices,
                     "price"   => $product->getPrice() 
                   )
                );
         if ($request->isMethod('POST')) {
            $form->bind($request);
            if ($form->isValid()) {
              // ... standard symfony stuff here
            }
         }
        return array(
            'form' => $form->createView()
        );
     }
    

    现在是表单类。注意事件监听器部分和 setDefaultOptions 方法。

    // ProductType.php
    
    namespace Acme\ExampleBundle\Form;
    
    use Symfony\Component\Form\AbstractType;
    use Symfony\Component\Form\FormEvents;
    use Symfony\Component\Form\FormBuilderInterface;
    use Symfony\Component\OptionsResolver\OptionsResolverInterface;
    
    
    class ProductType extends AbstractType
    {
    
      public function buildForm(FormBuilderInterface $builder, array $options)
      {
        $formFactory = $builder->getFormFactory();
        $builder->addEventListener(
            FormEvents::PRE_SET_DATA,
            function (\Symfony\Component\Form\FormEvent $event) use ($formFactory) {
    
                    // get the option array passed from the controller
                    $options = $event->getData();
    
                    $choices = $options["choices"];
                    $event->getForm()->add(
                    // add a new element with radio buttons to the form
                    $formFactory->createNamed("my_dynamic_field_name", "choice", null, array(
                            "empty_value" => "Choose an option",
                            "label" => "My dynamic field: ",
                            "choices" => $choices
                        )
                    )
                );
    
            }
        );
    
        // ... add other form elements
        $builder->add("price", "text");
        // ..
     }
    
     public function setDefaultOptions(OptionsResolverInterface $resolver)
     {
        // register choices as a potential option
        $resolver->setDefaults(array(
            'choices' => null
        ));
     }
    }
    

    【讨论】:

      【解决方案2】:

      您不必在 $event 对象上设置 setData()。您必须实现 on POST_SET_DATA 逻辑,根据您的数据构建您的表单 the way you want

      然后您必须使用您的网络服务的回复来初始化您的表单(在您的控制器内)。

      注意: SET_DATA 表单事件自 2.1 版起已弃用。肯定会在 2.3 版中删除)

      更新:

      您可以将数组设置为表单数据并使用DataTransformer 以您想要的方式构建表单数据。看看上次旧金山 Symfony Live 期间的 Data Transformation partSymfony 2 Form Tricks

      【讨论】:

      • 目前我正在初始化我的学说实体然后传递它。 :$product = new Product(); $form = $this->createForm(new ProductType(), $product);。向产品实体添加伪属性、使用来自 Web 服务的信息进行设置并传递此扩展产品实体的方法是否正确?
      • @jamie0726 所以你的表单使用了一个产品对象+他通过网络服务获得的额外字段,对吧?
      • 完全正确 :-) 用户选择将作为“普通”实体属性存储在数据库中的额外选项之一。
      • 这是一个很棒的演讲,感谢您的链接,尽管 Bernhard 说 DataTransformers 不应该用于动态表单事件,仅用于视图、规范化和(忘记第三个)数据模型之间的转换。还是我弄错了?
      • @jamie0726 没错,我认为您可以只使用数据转换器来格式化您的数据($product + 额外字段),以保持您的代码干净。我认为没有必要通过事件来管理它。
      猜你喜欢
      • 2013-05-13
      • 1970-01-01
      • 2011-08-31
      • 1970-01-01
      • 1970-01-01
      • 2011-09-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多