symfonysymfony-formssymfony-2.4

Symfony2 - Display a form recursively


Hello everybody (please excuse my English).

I want to do an application which needs to allow that the users must fill out on a form their personal data, their children, grandchildren and great-grandchildren (a little family tree).

class Person
{
/**
 * @var int
 *
 * @ORM\Id
 * @ORM\GeneratedValue
 * @ORM\Column(type="integer")
 */
private $id;

/**
 * @var string
 *
 * @ORM\Column(type="string")
 */
private $firstname;

/**
 * @var string
 *
 * @ORM\Column(type="string")
 */
private $lastname;

/**
 * @var \DateTime
 *
 * @ORM\Column(type="datetime")
 */
private $dateOfBirth;

/**
 * @var Person
 *
 * @ORM\ManyToMany(targetEntity="Person")
 */
private $children;


public function __construct()
{
    $this->children = new ArrayCollection();
}

}
}

In the PersonType class, I do the following:

class PersonType extends AbstractType
{
/**
 * @param FormBuilderInterface $builder
 * @param array $options
 */
public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder->add('firstname');

    $builder->add('lastname');

    $builder->add('dateOfBirth');

    $builder->add('children', 'collection', array(
        'type'          => new PersonType(),
        'allow_add'     => true,
        'by_reference'  => false,)
    );
}

/**
 * @param OptionsResolverInterface $resolver
 */
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
    $resolver->setDefaults(array(
        'data_class' => 'Anything\YourBundle\Entity\Person'
    ));
}

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

In this way, I use the PersonType in the controller as below:

public function newAction()
{
    $entity = new Person();
    $form = $this->createForm(new PersonType(), $entity, array(
        'action' => $this->generateUrl('person_create'),
        'method' => 'POST',
    ));

    return array(
        'entity' => $entity,
        'form'   => $form->createView(),
    );
}

But the problem is when I request the url of this action, and the view of this action has to be rendered, there is a problem because doesn't give a response, because is in a infinite loop (I think that is the reason). I would like to know if is this possible to do using the Symfony forms, or if I have to look at other alternatives. If this was possible, how could I do that and how could I limit the form to only render the four levels that I need (me, my children, my grandchildren and my great-grandchildren)??

I hope that the problem has been understood.

Thanks in advance.


Solution

  • Thanks for the answer Ferdynator!!

    I didn't solve the problem in the way you proposed, but that approach helped me. I passed the recursion level in the constructor of the Person form, and thus, I could know when I had to stop:

    class PersonType extends AbstractType
    {
        private $recursionLevel;
    
        public function __construct( $recursionLevel ){
            $this->recursionLevel = $recursionLevel;
        }
    
        /**
         * @param FormBuilderInterface $builder
         * @param array $options
         */
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            if($this->recursionLevel > 0)
            {
                $builder->add('children', 'collection', array(
                    'type'          => new PersonType(--$this->recursionLevel),
                    'allow_add'     => true,
                    'by_reference'  => false,)
                );
            }
        }
    }