Symfony2表单组件可变形式数据用于调查

时间:2014-11-18 16:20:34

标签: php forms symfony symfony-forms

我想创建一个由多个问题(不同的实现类)组成的调查。 我很乐意将Survey创建以及所有问题表示为FormType,以便从Symfony Form Component中轻松获得验证和所有好东西。 嵌套described here等表单非常容易。

但现在是棘手的部分:

每个问题都有自己的FormType,并且应该在一个页面上创建和回答(由调查接受者填写)。所以在一页上的所有问题。或多或少,这就像Google表单一样,能够快速地在一个页面上添加新问题,并使用户能够轻松地一次查看所有问题。

我的2个问题是:

  1. 如何添加在运行时已知嵌套类型的FormType(管理员可以选择要添加的问题类型)?
  2. 当调查接受者填写调查表时,如何在一个页面上验证并存储所有表格?
  3. 我很想听听你的一些想法。

    谢谢, 卢卡斯

1 个答案:

答案 0 :(得分:4)

  1. 使用听众的力量。您可以使用CollectionTypeResizeListener使用的流程几乎相同的流程。

    public function preSetData(FormEvent $event)
    {
        $form = $event->getForm();
        $data = $event->getData();
        ...
        foreach ($data as $name => $value) {
            $form->add($name, $this->getTypeByClass($value), array_replace(array(
                'property_path' => '['.$name.']',
            ), $this->options));
        }
    }
    
    ...
    
    public function preSubmit(FormEvent $event)
    {
        $form = $event->getForm();
        $data = $event->getData();
        ...
        if ($this->allowAdd) {
            foreach ($data as $name => $value) {
                if (!$form->has($name)) {
                    // put special value into sub-form to indicate type of the question
                    $type = $value['type'];
                    unset($value['type']);
    
                $form->add($name, $type, array_replace(array(
                    'property_path' => '['.$name.']',
                ), $this->options));
            }
        }
    }
    

    }

    尝试使用allowDelete,allowAdd features实现非常相似的流程。

  2. 应该有其他类SurveyData.{items, survey, ...}与调查的n-1关系,SurveyItem.{answer, ...}QuestionAnswer的n-1关联。在您的结构的基础上应该有书面验证器。

    可以使用Valid约束来触发级联验证。

    http://symfony.com/doc/current/reference/constraints/Valid.html

  3. <强>更新

    1. 如何形成可变部分。

      public function buildForm(FormBuilderInterface $builder, array $options)
      {
          if ($options['allow_add'] && $options['prototyped']) {
              // @var ['prototype_name' => '__name__', 'type' => 'question_type']
              foreach ($options['prototypes'] as $prototype) {
                  $prototype = $builder->create($prototype['prototype_name'], $options['type'], $options['options']);
                  $prototype->add('type', 'hidden', ['data' => $options['type'], 'mapped' => false]);
                  $prototypes[$options['type']] =  $prototype->getForm();
              }
              $builder->setAttribute('prototypes', $prototypes);
          }
          ...
      }
      
      public function buildView(FormView $view, FormInterface $form, array $options)
      {
          $view->vars = array_replace($view->vars, array(
              'allow_add'    => $options['allow_add'],
              'allow_delete' => $options['allow_delete'],
          ));
      
          if ($form->getConfig()->hasAttribute('prototypes')) {
              $view->vars['prototypes'] = $form->getConfig()->getAttribute('prototypes')->createView($view);
          }
      }
      

      现在可以在树枝的form块中使用原型。

      {% for key, prototype in prototypes %}
           {% set data_prototypes[key] = form_row(prototype) %}
      {% endfor %}
      {% set attr = attr|merge({'data-prototypes' : data_prototypes|json_encode })
      

      现在你不需要JS中的ajax请求 - 只需使用原型。

      (var collection = $('your_collection')).append(collection.data('prototypes')[question_type].replace(/__name__/g, counter+1));
      

      您已将元素添加到集合中,现在管理员可以填充它并提交表单。其余的工作(将数据映射到课堂)将由Symfony完成。