Reputation: 3539
I've been trying to follow the tutorial to embed a form in another one. What I'm trying to do here is add a task, and add multiple categories to it. I'm using the example at http://symfony.com/doc/current/book/forms.html#embedding-a-single-object, but I added some ORM annotations to make the relation many-to-many. As such, here is my code for the Task & Category entities:
<?php
namespace Acme\TaskBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Task
*
* @ORM\Table()
* @ORM\Entity
*/
class Task
{
/**
* @ORM\ManyToMany(targetEntity="Category", inversedBy="tasks")
* @ORM\JoinTable(name="tasks_categories")
*
* @Assert\Type(type="Acme\TaskBundle\Entity\Category")
*/
protected $categories;
// ...
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
*
* @ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* @param string $name
* @return Task
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Constructor
*/
public function __construct()
{
$this->categories = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Add categories
*
* @param \Acme\TaskBundle\Entity\Category $categories
* @return Task
*/
public function addCategorie(\Acme\TaskBundle\Entity\Category $categories)
{
$this->categories[] = $categories;
return $this;
}
/**
* Remove categories
*
* @param \Acme\TaskBundle\Entity\Category $categories
*/
public function removeCategorie(\Acme\TaskBundle\Entity\Category $categories)
{
$this->categories->removeElement($categories);
}
/**
* Get categories
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getCategories()
{
return $this->categories;
}
}
<?php
namespace Acme\TaskBundle\Entity;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\ORM\Mapping as ORM;
/**
* Category
*
* @ORM\Table()
* @ORM\Entity
*/
class Category
{
/**
* @ORM\ManyToMany(targetEntity="Task", mappedBy="categories")
*/
private $tasks;
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
*
* @ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* @param string $name
* @return Category
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Constructor
*/
public function __construct()
{
$this->tasks = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Add tasks
*
* @param \Acme\TaskBundle\Entity\Task $tasks
* @return Category
*/
public function addTask(\Acme\TaskBundle\Entity\Task $tasks)
{
$this->tasks[] = $tasks;
return $this;
}
/**
* Remove tasks
*
* @param \Acme\TaskBundle\Entity\Task $tasks
*/
public function removeTask(\Acme\TaskBundle\Entity\Task $tasks)
{
$this->tasks->removeElement($tasks);
}
/**
* Get tasks
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getTasks()
{
return $this->tasks;
}
}
Both forms have been auto-generated by using the doctrine:generate:form
command. I changed the TaskType form to include the categories:
<?php
namespace Acme\TaskBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class TaskType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('categories', new CategoryType())
;
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Acme\TaskBundle\Entity\Task',
'cascade_validation' => true,
));
}
public function getName()
{
return 'task';
}
}
Now when I go to the create page for tasks, I get this error:
The form's view data is expected to be an instance of class Acme\TaskBundle\Entity\Category, but is an instance of class Doctrine\Common\Collections\ArrayCollection. You can avoid this error by setting the "data_class" option to null or by adding a view transformer that transforms an instance of class Doctrine\Common\Collections\ArrayCollection to an instance of Acme\TaskBundle\Entity\Category.
I honestly have no idea how to fix it since this seemed a pretty straight-forward thing but apparently it isn't. Could someone help me out here please?
Upvotes: 0
Views: 1564
Reputation: 635
in your Task Entity
remove the validation for categories.
Symfony tries to validate a ArrayCollection as one Category!(hence the error)
* @Assert\Type(type="Acme\TaskBundle\Entity\Category")
*/
$categories;
It isn't necessary since it is a collection. (validation will be based on what type of objects are in the collection)
If you created a CategoryType form then this form should return Acme\TaskBundle\Entity\Category
for it's data class.
class CategoryType {
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Acme\TaskBundle\Entity\Category',
.....
));
}
}
Also, in your TaskType
$builder
->add('name')
->add('categories', new CategoryType()) // new CategoryType()
// is not really needed here,
// symfony will automatically detect
// it's relation and create a new
// CategoryType if necessary.
Upvotes: 2