我正在尝试处理一个对我来说相当复杂的表格......
我们有收藏品,其中包含书籍(OneToMany),文章(OneToMany)及其作者(ManyToMany)。
用户可以编辑书籍:他可以添加或删除文章,并为每篇文章添加或删除一些作者。有嵌套表单:book> article> author。 如果作者是Collection中的新成员,则会为该Collection创建它。
实体描述看起来很好,数据库是由控制台生成的,看起来是一致的。
如果我不需要使用书籍版本表格来处理作者,这样就可以了。如果作者存在,我有一个重复的条目错误。如果作者是新的,我有一个“明确地坚持新实体或在关系上配置级联持久化操作”的错误。
以下是代码:
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();
}
我不知道如何使用级联。但是$ article-> addAuthor()应该调用$ authors-> addArticle():
文章实体摘录
/**
* @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);
}
答案 0 :(得分:2)
foreach声明中的逻辑是错误的。假设我们有下一位作者:
因此,对于每个现有作者(John和Eric),脚本都是通过新作者循环的:
foreach ([John, Eric] as $author) {
foreach([Ada, Eric] as $newAuthor) {
// John author: the script persist Ada(right) and Eric(wrong) as new authors
// Eric author: the script persist Ada(wrong), but not Eric(right)
}
}
解决方案是用现有作者替换文章作者(如果有类似的话)
foreach ($article->getAuthors() as $key => $articleAuthor) {
$authorUrlname=$this->mu->generateUrlname($articleAuthor->getFirstname().' '.$articleAuthor->getLastname());
$foundAuthor = false;
// Compare article author with each existing author
foreach ($this->collectionWithAuthors->getAuthors() as $existAuthor) {
if ($existAuthor->getUrlname() == $authorUrlname) {
$foundAuthor = true;
break; // It has found similar author no need to look further
}
}
// Use $existAuthor as found one, otherwise use $articleAuthor
if ($foundAuthor) {
$article->removeAuthor($articleAuthor); // Remove submitted author, so he wont be persisted to database
$article->addAuthor($existAuthor);
} else {
// Here you dont need to create new author
$articleAuthor->setCollection($this->collectionWithBaseArticles);
$articleAuthor->setUrlname($authorUrlname);
}
...
}
$this->_em->persist($article);
你注意到我删除了循环中的任何作者持久性,以便在这些作者中更好地设置文章实体类的$ authors注释中的cascade = {'persist'}
/**
* @ORM\ManyToMany(targetEntity="Author", cascade={"persist"})
* @ORM\JoinTable(...)
*/
protected $authors;
<强> UPD:强>
我忘记提及有关级联持久性的一件事。为了保持文章和作者之间的关系,你还必须添加与作者实体的关系。修改addAuthor()
实体中的Article
方法,如下所示:
public function addAuthor(Author $author)
{
// Only add author relation if the article does not have it already
if (!$this->authors->contains($author)) {
$this->authors[] = $author;
$author->addArticle($this);
}
}
此外,最好为构造函数中的实体集合定义默认值:
use Doctrine\Common\Collections\ArrayCollection;
// ...
public function __construct()
{
$this->authors = new ArrayCollection();
}