Doctrine2 - 保存自定义连接关系表

时间:2013-01-07 15:45:56

标签: php doctrine-orm database-relations

基本上,我有两个表(文章和标签),我想要多对多(一篇文章可以有很多标签,一个标签可以分配给许多文章)与一些额外属性的关系。 我可以在Doctrine2中将它写成两个独立的关系(一对多,多对一)和一个关系表ArticleTag与我的额外属性。

我的问题是我不知道是否可以让Doctrine2为我创建连接表实体。我的意思是当我打电话时:

$article = /* create new article, etc... */
$tag = /* create new tag, etc... */
$article->addTag($tag);

$em->persist($article);
$em->flush();

DOES 在数据库中同时创建Article和Tag实体,但不会创建ArticleTag实体(换句话说,它不会创建Article和标签)。我可以自己创造它,但我宁愿依赖Doctrine2 当然,当我使用Doctrine2生成的标准连接表时,它工作正常,但我需要这些额外的属性。

有没有人有任何想法,或者我真的必须手动完成吗?

编辑:源代码

/**
 * @ORM\Entity
 */
class Article {
    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    protected $id;

    /**
     * @ORM\OneToMany(targetEntity="Tag", mappedBy="article", cascade={"persist"})
     * @ORM\JoinTable(name="ArticleTag", joinColumns={@ORM\JoinColumn(name="article_id", referencedColumnName="id")})
     * )
     */
    protected $tags;

    ...
}

/**
 * @ORM\Entity
 */
class ArticleTag {

    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    protected $id;

    /**
     * @ORM\ManyToOne(targetEntity="Article")
     */
     private $article;

    /**
     * @ORM\ManyToOne(targetEntity="Tag")
     * @ORM\JoinColumn(name="tag_id", referencedColumnName="id")
     */
     private $tag;

    /**
     * @ORM\Column(type="float")
     */
    protected $priority = 0.5;

}

/**
 * @ORM\Entity
 */
class Tag {

    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    protected $id;

    /**
     * @ORM\Column(type="string", length=32)
     */
    protected $name;

}

2 个答案:

答案 0 :(得分:2)

本身没有办法自动执行此操作,但您可以将addTag类上的Article方法更改为以下内容:

public function addTag(Tag $tag, $priority)
{
    $articleTag = new ArticleTag();
    $articleTag->setTag($tag);
    $articleTag->setArticle($this);
    $articleTag->setPriority($priority);
    $this->addArticleTag($articleTag);
    return $this;
}

这样,您可以集中代码并隐藏ArticleTag条目的创建。有关其他解释,请参阅此逻辑背后的原因:

Doctrine眼中的一个类代表一个实体源,该类的每个实例代表一个实体。在简单的多对多表中,多对多表不是实体。实际上,它只是两个实体之间的关系,这就是为什么Doctrine允许你绕过这个逻辑,如果它只有外键就不需要ArticleTag实体。

但是,一旦向该表添加其他元数据,它就不再是关系表。我和很多看过不同东西的人讨论过这个问题,但事实并非如此。是的,它定义实体1和实体2是相关的,但该附加列定义了关联所需的其他元数据。因此,它本身就是一个实体,必须如此反映。

我一直在努力解决这段问题,直到最后我添加了上面显示的代码。

答案 1 :(得分:0)

我的实体可以在没有任何加入实体的情况下使用其标签(我的架构中的主题)加入文章,您是否因任何特定原因需要加入实体?

使用

$article->getSubjects()->add($subject);

实体

/**
 * @ORM\Entity(repositoryClass="\Fam\Article")
 * @ORM\Table(name="Article")
 */
class Article{

    /*StartProtected*/

        protected $links = array();

        public function __construct()
        {
            $this->subjects = new \Doctrine\Common\Collections\ArrayCollection();
        }

        /**
         * @ORM\ManyToMany(targetEntity="Subject")
         * @ORM\JoinTable(name="Article_to_Subject",
         *      joinColumns={@ORM\JoinColumn(name="articleId", referencedColumnName="articleId")},
         *      inverseJoinColumns={@ORM\JoinColumn(name="subjectId", referencedColumnName="subjectId")}
         *      )
         */
        protected $subjects;

        /**
         *
         * @return \Doctrine\Common\Collections\ArrayCollection 
         */
        public function getSubjects()
        {
            return $this->subjects;
        }        

        public function removeSubjects(){ $this->subjects = new \Doctrine\Common\Collections\ArrayCollection(); return $this;  }