3

我有一些使用闭包表模型存储的现有数据。我是 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/并在被调用时执行 SQL 以反映新添加的子项。$children$em->flush()

此处使用的一些 SQL 示例:

添加一个新的孩子:

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

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

如果这看起来确实是一种合理的方法,我想知道如何去攻击它?我更多的是寻找我需要将这些文件放在哪里/我需要如何设置类而不是有人给我一个实际的实现。任何可以帮助我入门的文档或示例将不胜感激。我对 Doctrine 的经验几乎为零——希望我在这里没有遗漏任何明显的东西。

4

1 回答 1

0

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

有一个 mongoDB 适配器,您还可以查看 DoctrinePHPCR 项目,该项目具有多个数据库的适配器。

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

希望有帮助。

于 2015-06-05T19:29:29.900 回答