Customize form collection rendering in Symfony

Form builder in Symfony is very powerfurl, you can easily build complex forms.

One of the best option is CollectionType, it means you can embed a collection of subforms (or Entities related) into a main form.

According to this documentation : https://symfony.com/doc/3.4/form/form_customization.html#how-to-customize-a-collection-prototype, you can customize displaying.
But, this documentation disappeared in Symfony 4.

To quickly display a collection into a very complex layout, you can use Twig blocks extensions, or directly customize your view.

Let’s suppose we have this form :

class TaskListType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options = array())
    {
        $builder->add('tasks', CollectionType::class, array(
            'entry_type' => TaskType::class,
        ));
    }
}

class TaskType
{
    public function buildForm(FormBuilderInterface $builder, array $options = array())
    {
        $builder
             ->add('content')
             ->add('active', CheckboxType::class);
    }
}

You can use these blocks to customize the layout :

{% block _task_list_entry_tasks_widget %}
      {# collection widgets of TaskType #}
{% endblock %}
{% block _task_list_entry_tasks_entry_widget %}
      {# inner label of TaskType #}
{% endblock %}
{% block _task_list_entry_tasks_entry_content_widget %}
      {# field content of TaskType #}
{% endblock %}
{% block _task_list_entry_tasks_entry_content_label %}
      {# label content of TaskType #}
{% endblock %}

Or in your view :

{% for task in formTaskList.tasks %}
    <div class="form-group row align-items-center">
        <label class="col-md-3 label-control">
            {# access task data using task.vars.data #}
            Task {{ task.vars.data['id'] }}
        </label>
        <div class="col-md-6">
            {{ form_widget(task.children.content) }}
        </div>
        <div class="col-md-1">
            {{ form_widget(task.children.active) }}
        </div>
    </div>
{% endfor %}

And if you need to pass options of the main form to the child form :

class TaskListType extends AbstractType 
{  
     public function buildForm(FormBuilderInterface $builder, array $options = array())  
     {  
          $builder->add('tasks', CollectionType::class, array(  
               'entry_type' => TaskType::class, 
               'entry_options' => [
                   'label' => null,
                   // access $options['colorsList'] in TaskType
                   'colorsList' => $options['colorsList']
                ],
          ));  
     } 
}

Laissez un commentaire