dongzhan7253 2017-03-21 16:51
浏览 79
已采纳

Symfony2:如何将使用工厂构建器创建的表单添加到另一个表单的集合类型字段中?

I am creating forms from yml at runtime. I go through the elements in yml file and add appropriate fields to the form. The root form is created like this

$form = $factory->createBuilder("form", $this->userData);

The yml will have an option to define a collection field as well. The collection field requires type option to be supplied which must be of type string, Symfony\Component\Form\ResolvedFormTypeInterface, Symfony\Component\Form\FormTypeInterface

But since I am building the embedded form as well at runtime, I wont have a type and neither FormTypeInterface

Here is the sample code of what I need to do

$options = isset($config["options"]) ? $config["options"]: [];
if ($config['type'] == 'collection') {
    $options['type'] = $this->buildForm($options['template'], $factory);
    unset($options['template']);
    $form->add($config["name"], $config["type"], $options);
}

Here $options['template'] is how the type for the embedded form is defined in yml file. So that form is also build at runtime. How do I embed it in the root form?

Edit: In fact, if I only have a single field, say email in the collection field, then it works fine. But the yml spec will allow users to define multiple fields within collection fields. In symfony, this would be done by defining the embedded form type and setting type option of collection field type to that form type. But how do I do it when creating forms at runtime?

  • 写回答

1条回答 默认 最新

  • dtkp51520 2017-03-22 06:26
    关注

    I solved it by defining a form type class, that builds the form at runtime. The config(form design) is passed into the constructor and buildForm adds respective fields according to the design.

    class RuntimeFormType extends AbstractType
    {
        /**
         * @var string
         */
        private $name;
    
        /**
         * @var array
         */
        private $config;
    
        /**
         * RuntimeFormType constructor.
         * @param string $name
         * @param array $config
         */
        public function __construct($name, array $config)
        {
            $this->name = $name;
            $this->config = $config;
        }
    
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            foreach($this->config as $config){
                $options = isset($config["options"]) ? $config["options"]: [];
    
                if($config['type'] == 'image'){
                    $options['data_class']  = null;
                    $options['multiple']  = false;
    
                    $options['attr'] = [
                        "accept" => "images/*"
                    ];
    
                    $builder->add($config["name"], "file", $options);
                }else{
                    $builder->add($config["name"], $config["type"], $options);
                }
            }
        }
    
    
        public function getName()
        {
            return $this->name;
        }
    }
    

    and in the builder, when the type is collection type initialize this form type and add to the root form.

    if ($config['type'] == 'collection') {
        $template = $options['template'];
    
        unset($options['template']);
        $options['type'] = new RuntimeFormType($config["name"], $template);
    
        $form->add($themeConfig["name"], $themeConfig["type"], $options);
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?