ibi0tux
ibi0tux

Reputation: 2619

Symfony2 : How to validate and persist an array of entities (collection form)?

In my app I have a main form embedding a collection of forms.

My goal is to have a page on which I have a grid form with, for each line a different instance of Category entity, and at rows the fields value1, value2, value3.

I suceed to create the Category formtype, the Categories formtype, which is a collection of Category forms and the rendering of the form in the page work fine, and the values within the form match persisted data.

Here is the code :

Acme\APPBundle\Form\Type\Category.php ...

class CategoryType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder -> add ( 'value1' , 'text' )
                 -> add ( 'value2' , 'text' )
                 -> add ( 'value3' , 'text' )
                 -> add ( 'id', 'hidden')
        ;
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'Acme\APPBundle\Entity\Category',
        ));
    }

    public function getName()
    {
        return 'category';
    }
}
...

Acme\APPBundle\Form\Type\Category.php

class CategoriesType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('categories', 'collection', array('type' => new CategoryType()))
                ->add('save','submit');
    }


    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'validation_groups' => false
        ));
    }

    public function getName()
    {
        return 'categories';
    }
}

Acme\APPBundle\Controller\MainController.php

public function categoriesAction ( ) {
    $em = $this -> getDoctrine ( ) -> getManager ( );

    $categories = $em->getRepository('Acme\APPBundle\Entity\Category')->findAll();

    $form = $this -> createForm ( new CategoriesType ( ) , array('categories'=>$categories) );
    $form -> handleRequest ( $this -> getRequest ( ) );

    if ( $form -> isValid ( ) ) {
        $em -> persist ( $form );
        $em -> flush ( );
    }

    return $this -> render (
        'AcmeAPPBundle:Admin:categories.html.twig' , 
        array ( 
            'form' => $form -> createView(),
        )
    );
 }

My problem now is that I am unable to persist modified data in form. The $form -> isValid ( ) in my controller returns false. I tried "manual" validation with :

$validator = $this      -> get ( 'validator' );
$errorList = $validator -> validate ( $form );

but I don't have any errors but the form is still considered as invalid. I also tried to bypass validation and directly persist the data but nothing happens.

Any clue ? Thanks

Upvotes: 0

Views: 1024

Answers (2)

ibi0tux
ibi0tux

Reputation: 2619

Thank you @satdev86 for your advice.

What was missing was probably cascade_validation and also the fact that I was trying to persist $form instead of the data.

Here is my functionnally code for those who might be interested :

Acme\APPBundle\Form\Type\Category.php

...
class CategoryType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder -> add ( 'value1' , 'text' )
                 -> add ( 'value2' , 'text' )
                 -> add ( 'value3' , 'text' )
                 -> add ( 'id', 'hidden')
        ;
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'Acme\APPBundle\Entity\Category',
            'csrf_protection' => false,
            'cascade_validation' => true,
        ));
    }

    public function getName()
    {
        return 'category';
    }
}
...

Acme\APPBundle\Form\Type\Categories.php

...
class CategoriesType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('categories', 'collection', array('type' => new CategoryType()))
                ->add('save','submit');
    }


    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'validation_groups' => false,
            'csrf_protection' => false,
            'cascade_validation' => true,
        ));
    }

    public function getName()
    {
        return 'categories';
    }
}
...

Acme\APPBundle\Controller\MainController.php

...
public function categoriesAction ( ) {
    $em = $this -> getDoctrine ( ) -> getManager ( );

    $categories = $em->getRepository('Acme\APPBundle\Entity\Category')->findAll();

    $form = $this -> createForm ( new CategoriesType ( ) , array('categories'=>$categories) );
    $form -> handleRequest ( $this -> getRequest ( ) );

    if ( $form -> isValid ( ) ) {
        foreach($form -> getData()['categories'] as $c) {
            $em -> persist ( $c );
        }
        $em -> flush ( );
    }

    return $this -> render (
        'AcmeAPPBundle:Admin:categories.html.twig' , 
        array ( 
            'form' => $form -> createView(),
        )
    );
 }
...

Upvotes: 0

satdev86
satdev86

Reputation: 810

Please try the following steps to pass validations.,

  • Set the data class to CategoriesType form.
  • Add "Valid" constraints to categories field in categories entity, this will validate the child class as well.
  • For debugging, to print errors from child class, Try $form->getErrors(true).
  • Cascade persist Categories entity instance using $em->persist($categories). Please note you cant persist form object.

This should solve your issue.

Upvotes: 2

Related Questions