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
A page can contain an infinity of forms.
Create a Form Model class — like TaskList
— that holds a collection of Task
s. Then create TaskListType
that holds a collection of TaskType
s. This way you'll have one form with as many tasks as you want.
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!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With