Tree

← Tree

Ashterix

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

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

1 + # Tree
2 +
3 + Дерево на основі materialized path: кожен вузол зберігає шлях від кореня (`/1/4`), а ієрархія збирається в пам'яті з плоскої вибірки.
4 +
5 + ## Сутність
6 +
7 + ```php
8 + use ArrayAccess;
9 + use Doctrine\ORM\Mapping as ORM;
10 + use Ufo\DoctrineBehaviors\Contract\Entity\TreeNodeInterface;
11 + use Ufo\DoctrineBehaviors\Model\Tree\TreeNodeTrait;
12 +
13 + #[ORM\Entity(repositoryClass: CategoryRepository::class)]
14 + class Category implements TreeNodeInterface, ArrayAccess
15 + {
16 + use TreeNodeTrait;
17 +
18 + #[ORM\Id, ORM\Column]
19 + private ?int $id = null;
20 +
21 + #[ORM\Column(nullable: true)]
22 + private ?string $name = null;
23 +
24 + public function __toString(): string
25 + {
26 + return (string) $this->name;
27 + }
28 +
29 + public function getId(): ?int
30 + {
31 + return $this->id;
32 + }
33 +
34 + public function setId(int $id): void
35 + {
36 + $this->id = $id;
37 + }
38 + }
39 + ```
40 +
41 + * Бандл мапить `materializedPath` (рядок 255). `parentNode` і `childNodes` не зберігаються — їх заповнює `buildTree()`.
42 + * `getNodeId()` за замовчуванням повертає `getId()`. Ідентифікатор потрібен **до** того, як вузол додають у дерево, інакше `setChildNodeOf()` кидає `TreeException` — тому в прикладі id задається вручну.
43 + * `ArrayAccess` необов'язковий: він дає доступ `$node[0]` до дочірніх вузлів, а `$node[] = $child` додає дочірній вузол.
44 +
45 + ## Репозиторій
46 +
47 + ```php
48 + use Doctrine\ORM\EntityRepository;
49 + use Ufo\DoctrineBehaviors\ORM\Tree\TreeTrait;
50 +
51 + class CategoryRepository extends EntityRepository
52 + {
53 + use TreeTrait;
54 + }
55 + ```
56 +
57 + | Метод `TreeTrait` | Що робить |
58 + | --- | --- |
59 + | `getTree(string $path = '')` | Вибирає вузли за шляхом і повертає перший (корінь) із побудованим деревом або `null`. |
60 + | `getFlatTree(string $path)` / `getFlatTreeQB()` | Плоский список / QueryBuilder вузлів, відсортованих за `materializedPath`. |
61 + | `getRootNodes()` / `getRootNodesQB()` | Вузли з порожнім `materializedPath`. |
62 + | `getTreeExceptNodeAndItsChildrenQB(TreeNodeInterface $node)` | Усі вузли, крім заданого і його нащадків (напр., для вибору нового батька). |
63 + | `buildTree(array $results)` | Будує дерево з готової плоскої вибірки. |
64 + | `addFlatTreeConditions(QueryBuilder $qb, array $extraParams)` | Порожній hook для додаткових умов вибірки. |
65 +
66 + `getTreeExceptNodeAndItsChildrenQB()` і `getFlatTreeQB()` звертаються до поля `id`, тож ідентифікатор має називатися саме так.
67 +
68 + ## Використання
69 +
70 + ```php
71 + $root = new Category();
72 + $root->setId(1);
73 +
74 + $child = new Category();
75 + $child->setId(2);
76 + $child->setChildNodeOf($root); // materializedPath = '/1'
77 +
78 + $entityManager->persist($root);
79 + $entityManager->persist($child);
80 + $entityManager->flush();
81 +
82 + $tree = $categoryRepository->getTree();
83 + $tree->getChildNodes(); // Collection
84 + $tree[0]; // перший дочірній вузол (з ArrayAccess)
85 + $tree->isRootNode(); // true
86 + $tree[0]->isLeafNode(); // true
87 + $tree[0]->getNodeLevel(); // 2
88 + ```
89 +
90 + Інші методи вузла: `getParentNode()`, `getRootNode()`, `isChildNodeOf()`, `isIndirectChildNodeOf()`, `getRealMaterializedPath()`, `toArray()`, `toFlatArray()`, `toJson()`. Роздільник шляху (`/`) змінюється перевизначенням статичного `getMaterializedPathSeparator()`.
91 +
92 + :::warning
93 + Новий вузол має порожній шлях, а `setChildNodeOf(null)` записує шлях `/`. Обидва вважаються коренями (`isRootNode()`), але `getRootNodes()` знаходить лише вузли з порожнім шляхом — див. [Відомі помилки](/docs/doctrine/doctrine-behaviors/known_issues/open).
94 + :::