I’m trying to handle a form which is quite complex for me…
We have Collections, which contain books (OneToMany), with articles(OneToMany) and their authors (ManyToMany).
The user can edit a book: he can add or remove an article, and add or remove some authors for each article. There are nested forms : book>article>author.
If the author is new in the Collection, it is created for that Collection.
Entities descriptions look fine, database is generated by the console and seems consistent.
This is working fine if I don’t have to deal with authors using the book edition form. If the author exists, I have a duplicate entry bug. If the author is new, I have a “Explicitly persist the new entity or configure cascading persist operations on the relationship” bug.
Here is the code:
public function onSuccess(Book $book)
{
$this->em->persist($book);
foreach($book->getArticles() as $article)
{
$article->setUrlname($this->mu->generateUrlname($article->getName()));
$article->setBook($book);
// Saving (and creating) the authors of the book
foreach ($this->collectionWithAuthors->getAuthors() as $existAuthor){
foreach($article->getAuthors() as $author) {
$authorUrlname=$this->mu->generateUrlname($author->getFirstname().' '.$author->getLastname());
if ( $existAuthor->getUrlname() == $authorUrlname) { // The author is existing
$article->addAuthor($existAuthor);
$this->em->persist($existAuthor);
}else{ // New Author
$newAuthor = new Author();
$newAuthor->setCollection($this->collectionWithBaseArticles);
$newAuthor->setLastname($author->getLastname());
$newAuthor->setFirstname($author->getFirstname());
$newAuthor->setUrlname($authorUrlname);
$this->em->persist($newAuthor);
$article->addAuthor($newAuthor);
}
}
}
$this->em->persist($article);
}
$this->em->flush();
}
I don’t know how to use cascades. But the $article->addAuthor() is supposed to call $authors->addArticle():
Article Entity extract
/**
* @ORM\ManyToMany(targetEntity="bnd\myBundle\Entity\Author", mappedBy="articles")
*/
private $authors;
/**
* Add authors
*
* @param bnd\myBundle\Entity\Author $authors
* @return Article
*/
public function addAuthor(\bnd\myBundle\Entity\Author $authors)
{
$this->authors[] = $authors;
$authors->addArticle($this);
}
The logic in foreach statement is wrong. Suppose we have next authors:
So for every existing author (John and Eric) the script loop thru new authors:
The solution is to replace article authors with existing authors (if there is similar)
You have noticed i removed any author persistent from the loop, to persist these authors its better to set cascade={‘persist’} in $authors annotation of Article Entity Class
UPD:
I forgot to mention one thing about cascade persistent. To persist relation betweed article and author you also have to add relation to author entity. Edit the
addAuthor()method in theArticleentity as below:Also, it’s a good practice to define default values for a collection of entities in the constructor: