I'm facing some issue when I try to persist a collection of entities using a symfony form. I followed the official documentation but I can't make it work becouse of this error:
Entity of type ProductItem has identity through a
foreign entity Product, however this entity has no identity itself. You have to call
EntityManager#persist() on the related entity and make sure that an identifier was
generated before trying to persist ProductItem. In case of Post Insert ID
Generation (such as MySQL Auto-Increment or PostgreSQL SERIAL) this means you
have to call EntityManager#flush() between both persist operations.
I have to entities linked with a OneToMany relation:
Product
/**
* @ORM\Column(name="id", type="integer", nullable=false)
* @ORM\Id
* @ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* @ORM\OneToMany(targetEntity="ProductItem", mappedBy="product",cascade={"persist"})
*/
protected $items;
And ProductItem
/**
* @ORM\Id()
* @ORM\ManyToOne(targetEntity="Product", inversedBy="items")
*/
protected $product;
/**
* @ORM\Id()
* @ORM\ManyToOne(targetEntity="Item")
*/
protected $item;
This is how it is added to the form:
->add('items','collection',array(
'label' => false,
'type' => new ProductItemType(),
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false))
And this is the controller action:
public function newAction()
{
$product= new Product();
$form = $this->createForm(new ProductType(), $product);
if($request->isMethod("POST"))
{
$form->handleRequest($request);
if($form->isValid())
{
$em = $this->getDoctrine()->getManager();
$em->persist($product);
$em->flush();
}
}
}
I'm doing something wrong for sure in the controller because, as the error message says, I have to persist $product before adding $productItems, but how can I do that?
I only get this error when trying to persist a new entity, if the entity has been persisted before, I can add as may items as I want successfully
Also faced this issue during the work with form to which CollectionType field was attached. The other one approach which could solve this problem and also mentioned in doctrine official documentation is following:
In simple words, you should provide product link to linked items manually - this is described in "Establishing associations" section of following article: http://docs.doctrine-project.org/en/latest/reference/working-with-associations.html#working-with-associations
You didn't follow the docs completely. Here is something you can do to test a single
item
, but if you want to dynamically add and delete items (it looks like you do), you will also need to implement all the javascript that is included in the docs that you linked to.So this should work for a single static
item
, but like I said, the dynamic stuff is a bit more work.IMO, your problem is not related to your controller but to your Entities. It seems your would like to make a ManyToMany between your Product and Item and not creating a ProductItem class which should behave as an intermediate object for representing your relation. Additionally, this intermediate object have no id generation strategy. This is why Doctrine explains you, you must first persist/flush all your new items and then persist/flush your product in order to be able to get the ids for the intermediate object.
The annotation is wrong... the cascade persist is on the wrong side of the relation
Another way to achieve this (e.g. annotation not possible) is to set the form by_reference
I had exact same problem last week, here is a solution I found after some reading and testing.
The problem is your Product entity has cascade persist (which is usually good) and it first try to persist
ProductItem
butProductItem
entities cannot be persisted because they require Product to be persisted first and its ID (Composite key (product, item).There are 2 options to solve this:
1st I didn't use it but you could simply drop a composite key and use standard id with foreign key to the
Product
2nd - better This might look like hack, but trust me this is the best what you can do now. It doesn't require any changes to the DB structure and works with form collections without any problems.
Code fragment from my code, article sections have composite key of (article_id, random_hash). Temporary set one to many reference to an empty array, persist it, add you original data and persist (and flush) again.