Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a collection of several fields without any custom Form Type class?

I have lots of collections to create, and don't want to create a FormType for each entry_type, because they are used only once.

So instead of giving a form type FQCN in the entry_type option, I tried to put a fresh Type directly coming from the form builder:

$type = $this
   ->get('form.factory')
   ->createBuilder(Type\FormType::class)
   ->add('label', Type\TextType::class, [
       'label' => 'Key',
   ])
   ->add('value', Type\TextType::class, [
       'label' => 'Value',
   ])
   ->getType()
;

$form = $this
   ->get('form.factory')
   ->createBuilder(Type\FormType::class)
   ->add('hash', Type\CollectionType::class, [
       'entry_type'    => $type,
       'entry_options' => [],
       'allow_add'     => true,
       'allow_delete'  => true,
       'prototype'     => true,
       'required'      => false,
       'delete_empty'  => true,
   ])
   ->getForm()
;

But for some reasons, the prototype is invalid:

<div class="form-group">
    <label class="control-label required">__name__label__</label>
    <div id="form_hash___name__"></div>
</div>

All child fields from my manually-created $type are missing. Where is my mistake?

like image 974
Alain Tiemblo Avatar asked Mar 13 '23 20:03

Alain Tiemblo


1 Answers

I found my answer myself finally.

As the ->getType() I was using is in the FormBuilder class, but not in the FormBuilderInterface, I assume this was a bad idea to use it. Moreover, the FormType instance returned was empty (a form type, but no children).

So I changed my stand and created the following EntryType class (yes, I'm using a Form Type class, but only a generic one for all my future collections):

<?php

namespace AppBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class EntryType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        foreach ($options['fields'] as $field) {
            $builder->add($field['name'], $field['type'], $field['options']);
        }
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'fields' => [],
        ]);
    }
}

I can now use arbitrary fields in my collection using this fields option:

use Symfony\Component\Form\Extension\Core\Type;
use AppBundle\Form\Type\EntryType;

// ...

$form = $this
   ->get('form.factory')
   ->createBuilder(Type\FormType::class)
   ->add('hash', Type\CollectionType::class, [
       'entry_type'    => EntryType::class,
       'entry_options' => [
           'fields' => [
               [
                   'name'    => 'key',
                   'type'    => Type\TextType::class,
                   'options' => [
                       'label' => 'Key',
                   ],
               ], [
                   'name'    => 'value',
                   'type'    => Type\TextType::class,
                   'options' => [
                       'label' => 'Value',
                   ],
               ],
           ],
       ],
       'allow_add'    => true,
       'allow_delete' => true,
       'prototype'    => true,
       'required'     => false,
       'delete_empty' => true,
   ])
   ->getForm()
;
like image 141
Alain Tiemblo Avatar answered Apr 26 '23 11:04

Alain Tiemblo