Tree

← Tree

Ashterix

docs: Doctrine section with Doctrine Behaviors and Doctrine Helper (uk + en)

uk/docs/doctrine/doctrine-behaviors/tree.md новий файл +94 −0

Tree

Дерево на основі materialized path: кожен вузол зберігає шлях від кореня (/1/4), а ієрархія збирається в пам'яті з плоскої вибірки.

Сутність

use ArrayAccess;
use Doctrine\ORM\Mapping as ORM;
use Ufo\DoctrineBehaviors\Contract\Entity\TreeNodeInterface;
use Ufo\DoctrineBehaviors\Model\Tree\TreeNodeTrait;

#[ORM\Entity(repositoryClass: CategoryRepository::class)]
class Category implements TreeNodeInterface, ArrayAccess
{
    use TreeNodeTrait;

    #[ORM\Id, ORM\Column]
    private ?int $id = null;

    #[ORM\Column(nullable: true)]
    private ?string $name = null;

    public function __toString(): string
    {
        return (string) $this->name;
    }

    public function getId(): ?int
    {
        return $this->id;
    }

    public function setId(int $id): void
    {
        $this->id = $id;
    }
}
  • Бандл мапить materializedPath (рядок 255). parentNode і childNodes не зберігаються — їх заповнює buildTree().
  • getNodeId() за замовчуванням повертає getId(). Ідентифікатор потрібен до того, як вузол додають у дерево, інакше setChildNodeOf() кидає TreeException — тому в прикладі id задається вручну.
  • ArrayAccess необов'язковий: він дає доступ $node[0] до дочірніх вузлів, а $node[] = $child додає дочірній вузол.

Репозиторій

use Doctrine\ORM\EntityRepository;
use Ufo\DoctrineBehaviors\ORM\Tree\TreeTrait;

class CategoryRepository extends EntityRepository
{
    use TreeTrait;
}
Метод TreeTrait Що робить
getTree(string $path = '') Вибирає вузли за шляхом і повертає перший (корінь) із побудованим деревом або null.
getFlatTree(string $path) / getFlatTreeQB() Плоский список / QueryBuilder вузлів, відсортованих за materializedPath.
getRootNodes() / getRootNodesQB() Вузли з порожнім materializedPath.
getTreeExceptNodeAndItsChildrenQB(TreeNodeInterface $node) Усі вузли, крім заданого і його нащадків (напр., для вибору нового батька).
buildTree(array $results) Будує дерево з готової плоскої вибірки.
addFlatTreeConditions(QueryBuilder $qb, array $extraParams) Порожній hook для додаткових умов вибірки.

getTreeExceptNodeAndItsChildrenQB() і getFlatTreeQB() звертаються до поля id, тож ідентифікатор має називатися саме так.

Використання

$root = new Category();
$root->setId(1);

$child = new Category();
$child->setId(2);
$child->setChildNodeOf($root);   // materializedPath = '/1'

$entityManager->persist($root);
$entityManager->persist($child);
$entityManager->flush();

$tree = $categoryRepository->getTree();
$tree->getChildNodes();          // Collection
$tree[0];                        // перший дочірній вузол (з ArrayAccess)
$tree->isRootNode();             // true
$tree[0]->isLeafNode();          // true
$tree[0]->getNodeLevel();        // 2

Інші методи вузла: getParentNode(), getRootNode(), isChildNodeOf(), isIndirectChildNodeOf(), getRealMaterializedPath(), toArray(), toFlatArray(), toJson(). Роздільник шляху (/) змінюється перевизначенням статичного getMaterializedPathSeparator().

Новий вузол має порожній шлях, а setChildNodeOf(null) записує шлях /. Обидва вважаються коренями (isRootNode()), але getRootNodes() знаходить лише вузли з порожнім шляхом — див. Відомі помилки.