简体   繁体   中英

Symfony2: How to add a form created using factory builder into another form's collection type field?

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?

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);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM