使用闭包表模型与Doctrine2进行分层数据

时间:2015-06-05 16:40:00

标签: php mysql symfony doctrine-orm transitive-closure-table

我使用closure table model存储了一些现有数据。我是Doctrine的新手,并试图为这个" Doctrine方式实现实体,并且不确定如何继续。我试图遵循的理念是,实体应该只是一个普通的PHP对象,并且应该使用某种注释来配置父子关联。

在这篇文章中,我将使用Category作为示例实体。这就是我想象的实体:

<?php

namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;

/**
 * @ORM\Table(name="categories)
 * @ORM\Entity
 */
class Category
{
    /**
     * @ORM\Column(name="categoryID", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $categoryID;

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

    /**
     * @MyORM\TreeParent(targetEntity="Category", closureTable="categories_paths", ancestorColumn="ancestorID", descendantColumn="descendantID")
     */
    protected $parent;

    /**
     * @MyORM\TreeChildren(targetEntity="Category", closureTable="categories_paths", ancestorColumn="ancestorID", descendantColumn="descendantID")
     */
    protected $children;

    public function __construct()
    {
        $this->children = new ArrayCollection();
    }

    public function getChildren()
    {
        return $this->children;
    }

    public function addChild(Category $child)
    {
        $this->children[] = $children;
    }

    public function getParent()
    {
        return $this->parent;
    }

    public function setParent(Category $parent)
    {
        $this->parent = $parent;
    }
}

闭包表如下所示:

categories_paths(ancestorID, descendantID, pathLength)

这个表基本上是一个连接表 - 它只存储父子关系,所以我不认为这里有一个实体是有意义的,类似于没有实体的方式与@JoinTable创建多对多关系时。

我希望能够像任何其他实体一样使用我的类别实体,当我从存储库中获取$parent / $children并且$em->flush()INSERT INTO categories_paths (ancestorID, descendantID, pathLength) SELECT a.ancestorID, d.descendantID, a.pathLength+d.pathLength+1 FROM categories_paths a, categories_paths d WHERE a.descendantID = $parentCategoryID AND d.ancestorID = $childCategoryID 时,我会填充// Delete all paths that end at $child DELETE a FROM categories_paths a JOIN categories_paths d ON a.descendantID=d.descendantID LEFT JOIN categories_paths x ON x.ancestorID=d.ancestorID AND x.descendantID=a.ancestorID WHERE d.ancestorID = $subtreeCategoryID and x.ancestorID IS NULL // Add new paths INSERT INTO categories_paths (ancestorID, descendantID, pathLength) SELECT parent.ancestorID, subtree.descendantID, parent.pathLength+subtree.pathLength+1 FROM categories_paths parent JOIN categories_paths subtree WHERE subtree.ancestorID = $subtreeCategoryID AND parent.descendantID = $parentCategoryID; / SELECT * FROM categories JOIN categories_paths cp ON cp.descendantID=categories.categoryID WHERE cp.ancestorID = $catogeryID AND cp.depth=1 调用,执行SQL以反映新添加的子项。

此处使用的SQL的一些示例:

添加一个新孩子:

location.reload();

将子树移动到新父级:

$.ajax({
  url: "test.html",
  context: document.body
}).done(function() {
  location.reload();
});

获取所有类别的孩子:

{{1}}

我在这里有几个问题。首先,这似乎是一种合理的方法/可以用Doctrine实现的东西吗?如果没有,是否有更好的方法来解决这个问题?

如果这看起来像是一种合理的方法,我想知道怎么去攻击这个?我正在寻找我需要放置这些文件的位置/我需要如何设置类而不是某人给我实际实现。任何有助于我入门的文档或示例都将非常感激。我对Doctrine的经验非常少 - 希望我不会错过任何明显的东西。

1 个答案:

答案 0 :(得分:0)

我认为如果你想建立一个分层数据库,你应该寻找教义ODM项目。您想要的所有内容都内置于其中,您可以自定义节点。

有一个mongoDB适配器,你也可以看看DoctrinePHPCR项目,它有多个数据库的适配器。

即使您想使用doctrine ORM实现自己的方法,您也可以查看它们的实现,以了解它们的工作原理。它们具有基于节点的关系,因此您始终可以引用对象树中的相邻节点。

希望有所帮助。