docs: Doctrine section with Doctrine Behaviors and Doctrine Helper (uk + en)
en/docs/doctrine/doctrine-behaviors/tree.md
new file +94
−0
Tree
A materialized-path tree: each node stores its path from the root (/1/4), and the hierarchy is assembled in memory from a flat result set.
Entity
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;
}
}
- The bundle maps
materializedPath(string 255).parentNodeandchildNodesare not persisted —buildTree()fills them. getNodeId()returnsgetId()by default. The identifier is needed before the node is added to a tree, otherwisesetChildNodeOf()throwsTreeException— that is why the example sets the id manually.ArrayAccessis optional: it gives$node[0]access to child nodes, and$node[] = $childadds a child node.
Repository
use Doctrine\ORM\EntityRepository;
use Ufo\DoctrineBehaviors\ORM\Tree\TreeTrait;
class CategoryRepository extends EntityRepository
{
use TreeTrait;
}
TreeTrait method |
What it does |
|---|---|
getTree(string $path = '') |
Selects nodes by path and returns the first one (the root) with the tree built, or null. |
getFlatTree(string $path) / getFlatTreeQB() |
Flat list / QueryBuilder of nodes sorted by materializedPath. |
getRootNodes() / getRootNodesQB() |
Nodes with an empty materializedPath. |
getTreeExceptNodeAndItsChildrenQB(TreeNodeInterface $node) |
All nodes except the given one and its descendants (e.g. to pick a new parent). |
buildTree(array $results) |
Builds a tree from a ready flat result set. |
addFlatTreeConditions(QueryBuilder $qb, array $extraParams) |
Empty hook for extra query conditions. |
getTreeExceptNodeAndItsChildrenQB() and getFlatTreeQB() refer to the id field, so the identifier must have exactly that name.
Usage
$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]; // first child node (with ArrayAccess)
$tree->isRootNode(); // true
$tree[0]->isLeafNode(); // true
$tree[0]->getNodeLevel(); // 2
Other node methods: getParentNode(), getRootNode(), isChildNodeOf(), isIndirectChildNodeOf(), getRealMaterializedPath(), toArray(), toFlatArray(), toJson(). The path separator (/) is changed by overriding the static getMaterializedPathSeparator().
A new node has an empty path, while setChildNodeOf(null) writes the path /. Both are treated as roots (isRootNode()), but getRootNodes() finds only nodes with an empty path — see Known issues.