双向自引用映射与原则2中的其他字段

时间:2016-04-14 15:40:29

标签: php doctrine-orm mapping self-reference bidirectional

我坚持这个。这是我得到的:

我获得了Document个权限,可以$previosDocuments$nextDocuments。这个关系是bidirectional,并且它们都是ArrayCollections。但我还需要了解其他一些补充信息。这就是为什么我得到一个DocumentRelation - 实体,其中包含其他字段。

注意:我知道下面的代码根本不正确。

到目前为止,这是我的代码:

/**
 * @ORM\Entity
 * @ORM\Table(name="document")
 */
class Document
{

    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

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

    /**
     * @var ArrayCollection $nextDocuments
     * @ORM\OneToMany(targetEntity="App\FrontEndBundle\Entity\DocumentRelation", mappedBy="document", cascade={"persist"})
     */
    protected $nextDocuments;

    /**
     * @var ArrayCollection $prevDocuments
     * @ORM\OneToMany(targetEntity="App\FrontEndBundle\Entity\DocumentRelation", mappedBy="targetDocument", cascade={"persist"})
     */
    protected $prevDocuments;

    /**
     * Document constructor.
     */
    public function __construct()
    {
        $this->prevDocuments = new ArrayCollection();
        $this->nextDocuments = new ArrayCollection();
    }

    /**
     * @param Document $nextDocument
     * @return $this
     */
    public function removeNextDocument($nextDocument)
    {
        if ($this->nextDocuments->contains($nextDocument)) {
            $this->nextDocuments->removeElement($nextDocument);
            $nextDocument->removePrevDocument($this);
        }
        return $this;
    }

    /**
     * @param Document $nextDocument
     * @return $this
     */
    public function addNextDocument($nextDocument)
    {
        if (!$this->nextDocuments->contains($nextDocument)) {
            $this->nextDocuments->add($nextDocument);
            $nextDocument->addPrevDocument($this);
        }
        return $this;
    }

    /**
     * @param Document $prevDocument
     * @return $this
     */
    public function addPrevDocument($prevDocument)
    {
        if (!$this->prevDocuments->contains($prevDocument)) {
            $this->prevDocuments->add($prevDocument);
            $prevDocument->addNextDocument($this);
        }
        return $this;
    }

    /**
     * @param Document $prevDocument
     * @return $this
     */
    public function removePrevDocument($prevDocument)
    {
        if ($this->prevDocuments->contains($prevDocument)) {
            $this->prevDocuments->removeElement($prevDocument);
            $prevDocument->removeNextDocument($this);
        }
        return $this;
    }
    //getter + setter 
}

/**
 * Class DocumentRelation
 * @package App\FrontEndBundle\Entity
 * @ORM\Entity
 * @ORM\Table(name="document_relation")
 */
class DocumentRelation
{

    /**
     * @var Document $targetDocument
     * @ORM\ManyToOne(targetEntity="App\FrontEndBundle\Entity\Document", inversedBy="id")
     * @ORM\JoinColumn(name="target_document_id", referencedColumnName="id")
     */
    protected $targetDocument;

    /**
     * @var Document $document
     * @ORM\ManyToOne(targetEntity="App\FrontEndBundle\Entity\Document", inversedBy="id")
     * @ORM\JoinColumn(name="document_id", referencedColumnName="id")
     */
    protected $document;

    [...] //$id & getter + setter 
}

我的问题是,我不知道如何让它们一起工作。 对于任何想法,帮助或暗示我会非常感激!

修改: 我最终想要的是一个具有双向关联的自引用实体和一些额外的字段来保存关于双向关系的一些额外信息。

编辑2 @ Kuba-Birecki:

public function indexAction()
{
   $this->createDocuments();

   return $this->render('AppFrontEndBundle:Default:index.html.twig');
}

private function createDocuments()
{
    $firstDocument = (new Document())->setName('first');
    $secondDocument = (new Document())->setName('second');

    $firstDocument->addNextDocument($secondDocument);
    $em = $this->getDoctrine()->getManager();
    $em->persist($firstDocument);
    $em->flush();
}

这是我尝试坚持它的方式,这也是我需要调用它的方式。

例外情况如下

  

在关联App \ FrontEndBundle \ Entity \ Document#nextDocuments上找到类型为App \ FrontEndBundle \ Entity \ Document的实体,但期待App \ FrontEndBundle \ Entity \ DocumentRelation

1 个答案:

答案 0 :(得分:0)

您的注释看起来不错,但您的业务逻辑并未反映这些规则。

$nextDocuments类的

Document应包含DocumentRelation的集合,但在您的方法中,您尝试在其中插入Document个对象。同样适用于$prevDocuments

您需要更改Document课程以使用DocumentRelation个对象而不是Document

class Document
{
    ...

    /**
     * @param DocumentRelation $relation
     * @return $this
     */
    public function removeNextDocument(DocumentRelation $relation)
    {
        if ($this->nextDocuments->contains($relation)) {
            $this->nextDocuments->removeElement($relation);
            $relation->setDocument(null);
        }

        return $this;
    }

    /**
     * @param DocumentRelation $relation
     * @return $this
     */
    public function addNextDocument(DocumentRelation $relation)
    {
        if (!$this->nextDocuments->contains($relation)) {
            $this->nextDocuments->add($relation);
            $relation->setDocument($this);
        }

        return $this;
    }

    /**
     * @param DocumentRelation $relation
     * @return $this
     */
    public function addPrevDocument(DocumentRelation $relation)
    {
        if (!$this->prevDocuments->contains($relation)) {
            $this->prevDocuments->add($relation);
            $relation->setTargetDocument($this);
        }

        return $this;
    }

    /**
     * @param DocumentRelation $relation
     * @return $this
     */
    public function removePrevDocument(DocumentRelation $relation)
    {
        if ($this->prevDocuments->contains($relation)) {
            $this->prevDocuments->removeElement($relation);
            $relation->setTargetDocument(null);
        }

        return $this;
    }
}

当然,这也意味着您必须先创建/获取这些DocumentRelation个对象,然后再将它们传递给这些方法。

然后,例如,如果您要通过直接传递而不是$prevDocuments来检查Document是否包含某个DocumentRelation,那么您可以这样做:

public function hasPrevDocument(Document $document)
{
    // Iterate over DocumentRelations
    foreach ($this->prevDocuments as $relation) {
        // Check if the relation refers to the wanted document
        if ($relation->getDocument() === $document) {
            return true;
        }
    }

    return false;
}

我希望这会有所帮助。