Tree

← Tree

Ashterix

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). parentNode and childNodes are not persisted — buildTree() fills them.
  • getNodeId() returns getId() by default. The identifier is needed before the node is added to a tree, otherwise setChildNodeOf() throws TreeException — that is why the example sets the id manually.
  • ArrayAccess is optional: it gives $node[0] access to child nodes, and $node[] = $child adds 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.