Reputation:
I'm having some trouble with bi-directional relations (one-to-many) when using the entity field type in Symfony 2.1. When creating the child (Product) and selecting the parent (Category), everything is hunky dory, it's created and persisted as expected. The issue comes when creating a parent (Category), and selecting multiple children (Product) checkboxes as generated by Symfony2's form system. This does not persist.
I'll put my example classes below, however it might be easier cloning my example project repo - https://github.com/domudall/multiple-expanded-entity-choice-issue
Category
class Category
{
protected $id;
protected $name;
/**
* @ORM\OneToMany(targetEntity="Product", mappedBy="category")
*/
protected $products;
public function __construct()
{
$this->products = new ArrayCollection();
}
public function addProduct($product)
{
if (!$this->products->contains($product)) {
$this->products->add($product);
$product->setCategory($this);
}
return $this;
}
public function setProducts($products)
{
foreach ($products as $product) {
$this->addProduct($product);
}
return $this;
}
public function removeProducts()
{
if ($this->products->contains($product)) {
$this->products->remove($product);
}
return $this;
}
}
Product
class Product
{
protected $id;
protected $name;
/**
* @ORM\ManyToOne(targetEntity="Category", inversedBy="products")
*/
protected $category;
public function setCategory(Category $category)
{
$this->category = $category;
$category->addProduct($this);
return $this;
}
public function getCategory()
{
return $this->category;
}
}
DefaultController
class DefaultController extends Controller
{
public function categoryCreateAction(Request $request)
{
$category = new Category();
$form = $this
->createFormBuilder($category)
->add('name', 'text', array())
->add('products', 'entity', array(
'class' => 'AcmeShopBundle:Product',
'property' => 'name',
'required' => false,
'expanded' => true,
'multiple' => true,
))
->getForm();
if ($request->getMethod() == 'POST') {
$this->save($category, $form, $request);
}
}
public function productCreateAction(Request $request)
{
$product = new Product();
$form = $this
->createFormBuilder($product)
->add('name', 'text')
->add('category', 'entity', array(
'class' => 'AcmeShopBundle:Category',
'property' => 'name',
'required' => false,
))
->getForm();
if ($request->getMethod() == 'POST') {
$this->save($product, $form, $request);
}
}
protected function save($entity, $form, $request)
{
$form->bind($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
}
}
}
Any pointers to where I'm going wrong would be greatly appreciated.
NOTE
I don't want to use Doctrine cascade
options, would rather have the logic in the entities for unit testing separate from the db.
Upvotes: 1
Views: 2266
Reputation: 3656
You have to manually persist these entities if you don't want to cascade.
I use collection's map()
method (below) but you can do it with foreach
or array_map
via the collection's toArray()
method.
Try the following controller code:
protected function saveCategory($category, $form, $request)
{
$form->bind($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$entity->getProducts()->map(
function($product) use ($em) {
$em->persist($product);
}
);
$em->persist($category);
$em->flush();
}
}
Upvotes: 2