У меня есть некоторые существующие данные, хранящиеся с использованием модель закрывающего стола. Я новичок в Доктрине, и пытаюсь реализовать сущность для этого «Пути доктрины», и не совсем уверен, как действовать дальше. Философия, которой я пытаюсь следовать, заключается в том, что Entity должен быть просто старым PHP-объектом, и что для настройки ассоциаций родитель-потомок необходимо использовать какую-то аннотацию.
В этом посте я буду использовать категорию в качестве примера сущности. Вот что я представляю, как выглядит сущность:
<?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? Если нет, есть ли лучший способ приблизиться к этому?
Если это кажется разумным подходом, мне интересно, как это атаковать? Я больше ищу, где мне нужно поместить эти файлы / как мне нужно настроить классы, а не кого-то, кто дает мне реальную реализацию. Любая документация или примеры, которые помогут мне начать работу, будут высоко оценены. У меня практически нулевой опыт работы с Doctrine — надеюсь, я не пропускаю ничего очевидного.
Я думаю, что если вы хотите построить иерархическую базу данных, вы должны искать проект доктрины ODM. Все, что вы хотите, встроено в это, и вы можете настроить свой узел.
Есть адаптер mongoDB, а также вы можете взглянуть на проект DoctrinePHPCR, в котором есть адаптеры для нескольких баз данных.
Даже если вы хотите реализовать свой собственный подход с использованием доктрины ORM, вы можете посмотреть на их реализации, чтобы понять, как они работают. Они имеют отношения на основе узлов, поэтому у вас всегда есть ссылки на соседние узлы в дереве вашего объекта.
Надеюсь, это поможет.
Других решений пока нет …