0

私は私にとって非常に複雑なフォームを処理しようとしています...

書籍(OneToMany)、記事(OneToMany)、およびその著者(ManyToMany)を含むコレクションがあります。

ユーザーは本を編集できます。記事を追加または削除したり、記事ごとに著者を追加または削除したりできます。ネストされたフォームがあります:book>article>author。作成者がコレクションに初めて参加する場合は、そのコレクション用に作成されます。

エンティティの説明は見栄えがよく、データベースはコンソールによって生成され、一貫しているように見えます。

ブックエディションフォームを使用して著者に対応する必要がない場合、これは正常に機能しています。著者が存在する場合、重複エントリのバグがあります。作成者が新しい場合、「新しいエンティティを明示的に永続化するか、関係に対してカスケード永続化操作を構成する」というバグがあります。

コードは次のとおりです。

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);
}
4

1 に答える 1

2

foreachステートメントのロジックが間違っています。次の著者がいるとします。

  1. 永続化された作成者(collectionWithAuthors):
    • ジョン
    • エリック
  2. 投稿者
    • エイダ
    • エリック

したがって、既存のすべての作成者(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);

ループから永続的な作成者を削除したことに気づきました。これらの作成者を永続化するには、ArticleEntityClassの$authorsアノテーションにcascade={'persist'}を設定する方がよいでしょう。

/**
 * @ORM\ManyToMany(targetEntity="Author", cascade={"persist"})
 * @ORM\JoinTable(...)
 */
protected $authors;

UPD:

カスケード永続性について1つ言及するのを忘れました。記事と著者の間の関係を維持するには、著者エンティティへの関係も追加する必要があります。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();
}
于 2012-10-25T10:19:52.863 に答える