0

I haven´t found the solution to manually render a form which contains a collection. Here is my code in twig:

<ul id="document-fields-list" data-prototype="{{ form_widget(formulario.documentos.vars.prototype)|e }}">
    <div><button class="pull-right" href="#" id="add-another-document">Agregar documento</button></div>
    {% for documento in formulario.documentos %}
        <li>
            {{ form_label(documento) }}
            {{ form_widget(documento) }}
            <a href="#" class="remove-item">Eliminar</a>
        </li>
    {% endfor %}
</ul>
staskrak
  • 873
  • 2
  • 10
  • 22

1 Answers1

1

FormType

In your case we need to create formType for PersonaDocumento. Imagine, that this entity has field documentName:

class PersonaDocumentoType extends AbstractType
{
    /**
     * @param FormBuilderInterface  $builder
     * @param array                 $options
     * @SuppressWarnings(unused)
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('documentName', TextType::class, [
                'label'                 => false,
                'translation_domain'    => 'messages'
            ])
        ;
    }

    /**
     * @return string
     */
    public function getName()
    {
        return 'app_persona_documento_type';
    }

    /**
     * @return null|string
     */
    public function getBlockPrefix()
    {
        return 'app_persona_documento';
    }

    /**
     * @param OptionsResolver $resolver
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class'            => PersonaDocumento::class,
            'csrf_protection'       => true,
            'validation'            => true,
        ));
    }
}

Form that contain collection

Consider you entity Formulario. It has a OneToMany relation to PersonaDocumento. And Form will be:

class FormularioFormType extends AbstractType
{
    /**
     * @param FormBuilderInterface  $builder
     * @param array                 $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        // ...

        $builder
            ->add('documentos', CollectionType::class, [
                'entry_type'    => PersonaDocumentoType::class,
                'entry_options' => [
                    'label'         => false,
                ],
                'label'         => false,
                'allow_add'     => true,
                'allow_delete'  => true,
                'by_reference'  => false,  // Very important thing!
            ])
        ;
    }

    // ...
}

Widget for collection

We have a form (FormularioFormType) that contain collection of small forms with type PersonaDocumentoType.

New widget you can create in file with standard widgets, and name of the file is fields.html.twig : path_to_your_project/src/AppBundle/Resources/views/Form/fields.html.twig.

Name of the block will be app_persona_documento_widget.

Thus, example of fields.html.twig :

{% trans_default_domain 'messages' %}

{% block app_persona_documento_widget %}
    {% spaceless %}
        <div class="form-group" {{ block('widget_container_attributes') }}>
            <div class="col-sm-12">
                {{ form_widget(form.name, {'attr' : { 'placeholder' : 'app.form.label.name'|trans , 'class' : 'form-control' }}) }}
            </div>
        </div>
    {% endspaceless %}
{% endblock app_persona_documento_widget %}

Also pay attention that "app_persona_documento_widget" - assembled from the getBlockPrefix() of you PersonaDocumentoType plus string "_widget"

Register new form themes in config.yml

# Twig Configuration
twig:
    debug: '%kernel.debug%'
    strict_variables: '%kernel.debug%'
    form_themes:
        # other form themes
        # ...
        - 'AppBundle:Form:fields.html.twig'

Render collection in parent form

            {{ form_start(formulario_form) }}
                <div class="form-group">
                    <label for="" class="col-sm-2 control-label">
                        Label
                    </label>
                    <div class="col-sm-10 documentos" data-prototype="{{ form_widget(formulario_form.documentos.vars.prototype)|e('html_attr') }}">
                        {% for document in formulario_form.documentos %}
                            <div>
                                {{ form_widget(document) }}
                            </div>
                        {% endfor %}
                    </div>
                </div>
                <span>
                    {{ form_errors(formulario_form) }}
                </span>
                {#  Here you can add another fields of form   #}
            {{ form_end(formulario_form) }}

Of course, you also need buttons: one "Add another document" button and "Remove" buttons for each "Documento" item.

Symfony documentation suggests that we use JavaScript for this purpose. You can read more here in official docs

Also you can install Ninsuo/symfony-collection - A jQuery plugin that manages adding, deleting and moving elements from a Symfony collection

staskrak
  • 873
  • 2
  • 10
  • 22
  • I would like to know if there are another way, for example : changing something in some fixture in app/config because it is a preconfiguration of symfony. Thanks – Lucas Leonel Azzollini Jan 02 '18 at 13:36
  • And I don´t want to create this for all the collections and forms in my application – Lucas Leonel Azzollini Jan 02 '18 at 13:40
  • @LucasLeonelAzzollini, this is the official way. And there aren't any more convenient way to add collections. But! – staskrak Jan 02 '18 at 14:34
  • @LucasLeonelAzzollini BUT! you can install bundle for collections - Ninsuo/symfony-collection. You can find it on Packagist. This bundle provides for you navigation buttons (add and remove). – staskrak Jan 02 '18 at 14:35
  • I have just created the folder 'FORM' in path_to_your_project/src/AppBundle/Resources/views with the .twig inside and i also added the blockPrefix in DocumentoType but is not working and I have no errors and nothing that seems that the code works – Lucas Leonel Azzollini Jan 02 '18 at 16:17
  • @LucasLeonelAzzollini, I will edit my answer to provide more info – staskrak Jan 02 '18 at 16:48
  • @LucasLeonelAzzollini can you expose your Entity and Form? – staskrak Jan 02 '18 at 16:49
  • this is the type: ´->add('documentos', CollectionType::class, array( // each entry in the array will be "document" field 'entry_type' => PersonaDocumentoType::class, 'prototype' => true, 'allow_add' => true, 'allow_delete' => true, 'by_reference' => false, // these options are passed to each "document" type 'entry_options' => array('label' => false, 'attr' => array('class' => 'document-box') ),´ – Lucas Leonel Azzollini Jan 02 '18 at 17:54
  • and the entity : /** * @ORM\OneToMany(targetEntity="PersonaDocumento", cascade={"persist"},orphanRemoval=true) */ private $documentos; */ (The entity has get,add and remove methods) – Lucas Leonel Azzollini Jan 02 '18 at 17:56
  • @LucasLeonelAzzollini - I forgot to tell that you need to register your new theme in config.yml - watch that in edited answer – staskrak Jan 02 '18 at 19:38
  • Now I have an error when I acces the route of the form, "Unable to find template "AppBundle:Form:fields.html.twig" (looked into: E:\sympony-projects\fluo\app/Resources/views, E:\sympony-projects\fluo\vendor\symfony\symfony\src\Symfony\Bridge\Twig/Resources/views/Form)" – Lucas Leonel Azzollini Jan 02 '18 at 20:20
  • @LucasLeonelAzzollini then try to move `Form/fields.html.twig` to `app/Resources/views` – staskrak Jan 02 '18 at 20:26
  • I have just moved the folder and the error continues – Lucas Leonel Azzollini Jan 02 '18 at 22:50
  • @LucasLeonelAzzollini Did you registered new theme and config.yml and cleared the cache? – staskrak Jan 03 '18 at 09:34
  • yes I put the configuration you mencioned in config.yml, then I moved the twig to several paths and finally I cleared the cache to start the serve and the error continues – Lucas Leonel Azzollini Jan 03 '18 at 13:22
  • 1
    I solved the problem including form_theme in the twig – Lucas Leonel Azzollini Jan 03 '18 at 16:38
  • con you help me with this issue ? ir is very frustrating [https://stackoverflow.com/questions/48086257/symfony3-how-to-persist-an-object-with-its-collections/48098465?noredirect=1#comment83235243_48098465] – Lucas Leonel Azzollini Jan 06 '18 at 17:24