У меня есть некоторые существующие данные, хранящиеся с использованием closure table model. Я новичок в Doctrine и пытаюсь реализовать Entity для этого «Doctrine way» и не совсем уверен, как действовать. Философия, которой я пытаюсь следовать, заключается в том, что Entity должен быть просто старым PHP-объектом и что для настройки ассоциаций родитель-ребенок следует использовать некоторую аннотацию.Иерархические данные с Doctrine2 с использованием таблицы закрытия таблицы
В этом посте я буду использовать Категория в качестве примера. Вот что я себе лицо выглядит как:
<?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()
называется, есть SQL выполняется с учетом недавно добавленными детьми.
Некоторых примеров 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? Если нет, есть ли лучший способ приблизиться к этому?
Если это действительно разумный подход, мне интересно, как это сделать? Я больше ищу, где мне нужно поставить эти файлы/как мне нужно настроить классы, а кто-то дает мне реальную реализацию. Любая документация или примеры, которые помогут мне начать работу, будут высоко оценены. У меня почти нулевой опыт работы с Доктриной - надеюсь, я не пропущу ничего очевидного здесь.