Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to submit multiple forms of same type with one button in symfony2

I have the todolist where i display three forms of task type

$task1 = new Task();
$form1 = $this->createForm(new MyForm('f1'), $task1);

$task2 = new Task('fo');
$form2 = $this->createForm(new MyForm('f2'), $task2);

$task3 = new Task();
$form3 = $this->createForm(new MyForm('f3'), $task3);

Now the problem is i have one submit button only . How can i persist these three tasks within one controller. and user can add more forms dynamically as well.

so what the way to solve this

like image 607
Mirage Avatar asked Aug 01 '12 08:08

Mirage


People also ask

Can you have multiple forms within the same HTML document?

A page can contain an infinity of forms.


2 Answers

Create a Form Model class — like TaskList — that holds a collection of Tasks. Then create TaskListType that holds a collection of TaskTypes. This way you'll have one form with as many tasks as you want.

like image 72
Elnur Abdurrakhimov Avatar answered Nov 13 '22 23:11

Elnur Abdurrakhimov


For the sake of completeness find below a complete example.

You should create a new Model that represents the desired form. The point is that you probably don't want to affect Doctrine (eg. see doctrine:schema:update command). It might try to create a table for an entity that doesn't really exist. To avoid that, just put your model class under the Model folder (\src\Acme\Bundle\DemoBundle\Model\TaskList.php).

Assume that the following is your TaskType form class:

<?php

namespace Acme\Bundle\DemoBundle\Form;

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

class TaskType extends AbstractType
{
    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('id', null, array('read_only' => true))
            ->add('name');
    }

    /**
     * @param OptionsResolverInterface $resolver
     */
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(
            array(
                'data_class' => 'Acme\Bundle\DemoBundle\Entity\Task'
            )
        );
    }

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

This should be your TaskList model class:

<?php

namespace Acme\Bundle\DemoBundle\Model;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;

/**
 * Class TaskList
 * @package Acme\Bundle\DemoBundle\Model
 *
 * @ORM\Entity()
 */
class TaskList
{
    /**
     * @var \Doctrine\Common\Collections\ArrayCollection
     * @ORM\ManyToMany(targetEntity="\Acme\Bundle\DemoBundle\Entity\Task")
     */
    private $tasks;

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

    /**
     * @param \Acme\Bundle\DemoBundle\Entity\Task $task
     * @return $this
     */
    public function addTask(\Acme\Bundle\DemoBundle\Entity\Task $task)
    {
        $this->tasks[] = $task;

        return $this;
    }

    /**
     * @param \Acme\Bundle\DemoBundle\Entity\Task $task
     * @return $this
     */
    public function removeTask(\Acme\Bundle\DemoBundle\Entity\Task $task)
    {
        $this->tasks->remove($task);

        return $this;
    }

    /**
     * @return ArrayCollection
     */
    public function getTasks()
    {
        return $this->tasks;
    }

    /**
     * @param \Doctrine\Common\Collections\Collection $tasks
     * @return $this
     */
    public function setTasks(\Doctrine\Common\Collections\Collection $tasks)
    {
        $this->tasks = $tasks;

        return $this;
    }

    /**
     * @param \Knp\Component\Pager\Pagination\PaginationInterface $pagination
     * @return $this
     */
    public function setFromPagination(\Knp\Component\Pager\Pagination\PaginationInterface $pagination)
    {
        foreach ($pagination as $task) {
            $this->addTask($task);
        }

        return $this;
    }
}

And find below the TaskListType class:

<?php

namespace Acme\Bundle\DemoBundle\Form;

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

class TaskListType extends AbstractType
{
    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add(
                'tasks',
                'collection',
                array(
                    'type' => new \Acme\Bundle\DemoBundle\Form\TaskType(),
                )
            )
            ->add('save', 'submit');
    }

    /**
     * @param OptionsResolverInterface $resolver
     */
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(
            array(
                'data_class' => 'Acme\Bundle\DemoBundle\Model\TaskList'
            )
        );
    }

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

And your services.yml (optional):

services:
    acme.demo.form.type.task_list:
        class: Acme\Bundle\DemoBundle\Form\TaskListType
        tags:
            - { name: form.type, alias: acme_demo_task_list }

And a sample controller:

public function indexAction($page)
{
    ini_set('xdebug.max_nesting_level', 300); // this might be useful with deeply nested forms

    $search = $this->getRequest()->get(
        'search',
        array(
            'name' => '',
            'date' => '',
            'lang' => $this->container->getParameter('acme_core.default_lang')
        )
    );

    /**
     * @var \Doctrine\ORM\EntityManager $em
     */
    $em = $this->getDoctrine()->getManager();

    $paginator = $this->get('knp_paginator');
    $pagination = $paginator->paginate(
        $em->getRepository('AcmeDemoBundle:Task')->getQueryFilteringByLangNameAndDate(
            $search['lang'],
            $search['name'],
            $search['date'] != '' ? new \DateTime($search['date']) : null
        ),
        $page,
        $this->getRequest()->get('elementsPerPage', 10)
    );

    $taskList = new TaskList();
    $taskList->setFromPagination($pagination);

    $form = $this->createForm('acme_demo_task_list', $taskList); // "acme_demo_task_list" has been defined in the services.yml file
    $form->handleRequest($this->getRequest());

    if ($form->isValid()) {
        foreach ($form->getData() as $task) {
            $em->merge($task);
        }
        $em->flush();
    }

    return $this->render(
        'AcmeDemoBundle:Task:index.html.twig',
        array(
            'search' => $search,
            'pagination' => $pagination,
            'form' => $form->createView()
        )
    );
}

I hope this helps!

like image 24
Francesco Casula Avatar answered Nov 14 '22 00:11

Francesco Casula