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
+
:::