TreeTrait
Tree operations (nested set). A move and a delete rewrite `lft`/`rgt` on many rows (whole subtrees).
Cache invalidation happens in the manager after commit (explicit tag bump): tree operations
bypass the completed* hooks, so TreeTrait bumps
the class tag after a successful commit. The service only runs set-based SQL through the mapper.
Requires (like SaveTrait) $mapper; deleting additionally requires
DeleteTrait::deleteAll().
Table of Contents
Methods
- deleteTreeNode() : Result
- Deletes a node together with its whole subtree:
- getTreeSubtreeIds() : array<int, int>
- Returns ids of a node and all its descendants, for a caller that needs to know the subtree before deleting it (image cleanup, {@see \App\Core\Traits\Api\Models\Managers\TreeTrait::deleteNode()}).
- insertTreeNode() : Result
- Computes `lft`/`rgt`/`level` of a newly inserted node (after `save()`); delegates to the mapper.
- inTreeLock() : Result
- Runs the operation under the tree lock (table plus scope from the `TreeConfig`), so the manager holds the lock across the commit of its own transaction ({@see \App\Core\Traits\Api\Models\Managers\TreeTrait::treeTransaction()}).
- moveSubtree() : Result
- Moves a whole subtree under another parent; delegates to the mapper.
- moveTreeNode() : Result
- reorderTreeChildren() : Result
- Reorders the direct children of a parent into the given order; delegates to the mapper.
- deleteTreeNodeUnderLock() : Result
- requireTreeMapper() : TreeMapperInterface
- Mapper with tree operations; a service without a tree mapper has no such methods.
Methods
deleteTreeNode()
Deletes a node together with its whole subtree:
public
deleteTreeNode(int $id, TreeConfig $config) : Result
- collects the subtree ids (from leaves to root, safe for FKs),
- deletes them via DeleteTrait::deleteAll(): Doctrine remove (cascades, lifecycle) plus per-entity cache invalidation,
- closes the gap in
lft/rgtof the remaining nodes (set-based UPDATE).
A partial delete is an error: it returns a failure, and the manager holds the transaction (TreeTrait) and rolls it back.
IMPORTANT: the whole sequence runs under one tree lock: the bounds read in step 1 must stay
valid until the gap is closed in step 3 (the inner closeTreeGap lock is re-entrant).
Parameters
- $id : int
- $config : TreeConfig
Return values
ResultgetTreeSubtreeIds()
Returns ids of a node and all its descendants, for a caller that needs to know the subtree before deleting it (image cleanup, {@see \App\Core\Traits\Api\Models\Managers\TreeTrait::deleteNode()}).
public
getTreeSubtreeIds(int $id, TreeConfig $config) : array<int, int>
It locks and changes nothing; a missing node gives an empty array.
Parameters
- $id : int
- $config : TreeConfig
Return values
array<int, int>insertTreeNode()
Computes `lft`/`rgt`/`level` of a newly inserted node (after `save()`); delegates to the mapper.
public
insertTreeNode(int $id, TreeConfig $config) : Result
The manager bumps the cache tag after commit.
Parameters
- $id : int
- $config : TreeConfig
Return values
ResultinTreeLock()
Runs the operation under the tree lock (table plus scope from the `TreeConfig`), so the manager holds the lock across the commit of its own transaction ({@see \App\Core\Traits\Api\Models\Managers\TreeTrait::treeTransaction()}).
public
inTreeLock(TreeConfig $config, callable(): Result $operation) : Result
Parameters
- $config : TreeConfig
- $operation : callable(): Result
Return values
ResultmoveSubtree()
Moves a whole subtree under another parent; delegates to the mapper.
public
moveSubtree(int $id, int|null $newParentId, TreeConfig $config[, int|null $afterSiblingId = null ][, TreeMoveExpectation|null $expectation = null ]) : Result
The manager bumps the cache tag after commit.
Parameters
- $id : int
- $newParentId : int|null
-
null moves to the root level
- $config : TreeConfig
- $afterSiblingId : int|null = null
-
null = last child, 0 = first child, >0 = after that sibling
- $expectation : TreeMoveExpectation|null = null
-
client contract verified under the lock, null skips the check
Return values
ResultmoveTreeNode()
public
moveTreeNode(int $id, int $direction, TreeConfig $config) : Result
Parameters
- $id : int
- $direction : int
- $config : TreeConfig
Return values
ResultreorderTreeChildren()
Reorders the direct children of a parent into the given order; delegates to the mapper.
public
reorderTreeChildren(int|null $parentId, array<int, int> $orderedIds, TreeConfig $config) : Result
The manager bumps the cache tag after commit.
Parameters
- $parentId : int|null
-
null is the root level
- $orderedIds : array<int, int>
-
child ids in the new order
- $config : TreeConfig
Return values
ResultdeleteTreeNodeUnderLock()
private
deleteTreeNodeUnderLock(int $id, TreeConfig $config) : Result
Parameters
- $id : int
- $config : TreeConfig
Return values
ResultrequireTreeMapper()
Mapper with tree operations; a service without a tree mapper has no such methods.
private
requireTreeMapper() : TreeMapperInterface