1212/**
1313 * Nested set behavior for managing hierarchical data in {@see ActiveRecord} models.
1414 *
15- * Provides a set of methods and properties to implement the nested sets pattern in Yii {@see ActiveRecord} models,
16- * enabling efficient management of hierarchical data structures such as trees and categories.
15+ * Provides a set of methods and properties to implement the nested sets pattern in Yii Active Record model, enabling
16+ * efficient management of hierarchical data structures such as trees and categories.
1717 *
1818 * This behavior allows nodes to be inserted, moved, or deleted within the tree, and supports querying for parents,
1919 * children, leaves, and siblings.
2020 *
2121 * The behavior manages the left, right, and depth attributes of each node, and can optionally support multiple trees
2222 * using a tree attribute.
2323 *
24- * It integrates with a Yii event system and can be attached to any {@see ActiveRecord} model.
24+ * It integrates with a Yii Event system and can be attached to any {@see ActiveRecord} model.
2525 *
2626 * Key features.
2727 * - Compatible with Yii {@see ActiveRecord} and event system.
@@ -515,8 +515,6 @@ public function children(int|null $depth = null): ActiveQuery
515515 *
516516 * If the deletion fails, the transaction is rolled back to maintain data integrity.
517517 *
518- * @throws Exception if an unexpected error occurs during execution.
519- *
520518 * @return bool|int Number of rows deleted, or false if the deletion is unsuccessful.
521519 *
522520 * Usage example:
@@ -809,7 +807,6 @@ public function leaves(): ActiveQuery
809807 *
810808 * Sets the internal operation state to {@see self::OPERATION_MAKE_ROOT} and triggers the save process on the owner
811809 * model.
812- *
813810 * - If the attached {@see ActiveRecord} is a new record, this method creates it as the root node of a new tree,
814811 * setting `left=1`, `right=2`, and `depth=0`.
815812 * - If the record already exists, it moves the node to become the root node, updating the nested set structure
@@ -1094,7 +1091,7 @@ protected function moveNode(NodeContext $context): void
10941091
10951092 if ($ this ->treeAttribute === false || $ currentTreeValue === $ targetTreeValue ) {
10961093 $ this ->executeSameTreeMove ($ context , $ currentTreeValue );
1097- } elseif ( $ this -> treeAttribute !== false ) {
1094+ } else {
10981095 $ this ->executeCrossTreeMove ($ context , $ this ->treeAttribute , $ currentTreeValue , $ targetTreeValue );
10991096 }
11001097 }
@@ -1246,6 +1243,25 @@ private function deleteWithChildrenInternal(): bool|int
12461243 return $ result ;
12471244 }
12481245
1246+ /**
1247+ * Executes a cross-tree move operation for the current node and its descendants.
1248+ *
1249+ * Handles the relocation of a subtree from one tree to another in a multi-tree nested set structure, updating left,
1250+ * right, and depth attributes, and shifting affected nodes in the target tree to maintain integrity.
1251+ *
1252+ * This method is called internally when a node is moved across trees, ensuring that all boundaries and depth levels
1253+ * are recalculated and the subtree is correctly positioned in the new tree context.
1254+ *
1255+ * The operation performs the following steps.
1256+ * - Closes the gap left in the source tree by shifting left and right attributes of remaining nodes.
1257+ * - Moves the subtree to the target tree, updating tree, left, right, and depth attributes accordingly.
1258+ * - Shifts left and right attribute values in the target tree to make space for the incoming subtree.
1259+ *
1260+ * @param NodeContext $context Immutable context containing all movement data for the operation.
1261+ * @param string $treeAttribute Name of the tree attribute used for multi-tree support.
1262+ * @param mixed $currentTreeValue Value of the tree attribute for the current (source) tree.
1263+ * @param mixed $targetTreeValue Value of the tree attribute for the target tree.
1264+ */
12491265 private function executeCrossTreeMove (
12501266 NodeContext $ context ,
12511267 string $ treeAttribute ,
@@ -1284,6 +1300,27 @@ private function executeCrossTreeMove(
12841300 }
12851301
12861302 /**
1303+ * Executes a nested set operation on the current node with the specified target and operation type.
1304+ *
1305+ * Sets the internal operation state and target node reference, then save the owner model to perform the requested
1306+ * structural change in the tree.
1307+ *
1308+ * After saving, it refreshes the target or owner as needed to ensure updated attribute values for append and make
1309+ * root operations.
1310+ *
1311+ * This method is used internally by public API methods such as {@see appendTo()}, {@see insertAfter()},
1312+ * {@see insertBefore()}, {@see prependTo()}, and {@see makeRoot()} to centralize the execution logic for all
1313+ * supported nested set operations.
1314+ *
1315+ * @param ActiveRecord|null $targetNode Target node for the operation, or `null` if not applicable.
1316+ * @param string $operation Operation type to perform (see OPERATION_* constants).
1317+ * @param bool $runValidation Whether to perform validation before saving the record.
1318+ * @param array<string, mixed>|null $attributes List of attributes to save, or `null` for all attributes.
1319+ *
1320+ * @throws Exception if an unexpected error occurs during execution.
1321+ *
1322+ * @return bool Whether the operation was successful and the node was saved.
1323+ *
12871324 * @phpstan-param array<string, mixed>|null $attributes
12881325 */
12891326 private function executeOperation (
@@ -1308,6 +1345,25 @@ private function executeOperation(
13081345 return $ result ;
13091346 }
13101347
1348+ /**
1349+ * Moves the current node and its descendants to a new position within the same tree structure.
1350+ *
1351+ * Updates the left, right, and depth attributes for the node and all its descendants when moving a subtree to a
1352+ * different position within the same tree, ensuring the nested set structure remains consistent.
1353+ *
1354+ * The method performs the following operations.
1355+ * - Adjusts the left and right boundaries of the subtree if it is moved forward in the tree.
1356+ * - Closes the gap left by the moved subtree by shifting left and right attributes of remaining nodes.
1357+ * - Shifts left and right attribute values to make space for the moved subtree.
1358+ * - Updates left and right attributes for all nodes in the subtree to reflect the new position.
1359+ * - Updates the depth attribute for all nodes in the subtree based on the new target depth.
1360+ *
1361+ * This operation is essential for maintaining the integrity of the nested set hierarchy during node reordering
1362+ * and is used internally by movement operations that do not cross tree boundaries.
1363+ *
1364+ * @param NodeContext $context Immutable context containing all movement data for the operation.
1365+ * @param mixed $currentTreeValue Value of the tree attribute for the current tree.
1366+ */
13111367 private function executeSameTreeMove (NodeContext $ context , mixed $ currentTreeValue ): void
13121368 {
13131369 $ subtreeSize = $ this ->getRightValue () - $ this ->getLeftValue () + 1 ;
@@ -1381,18 +1437,38 @@ private function getDb(): Connection
13811437 return $ this ->db ??= $ this ->getOwner ()::getDb ();
13821438 }
13831439
1440+ /**
1441+ * Retrieves and caches the depth value of the current node.
1442+ *
1443+ * The value is cached on first access to avoid redundant lookups during nested set operations.
1444+ *
1445+ * This method is used internally by movement and update operations to determine the current node depth within the
1446+ * tree structure, ensuring correct calculation of depth offsets and validation of node positions.
1447+ *
1448+ * @return int Depth value of the current node as stored in the owner model.
1449+ */
13841450 private function getDepthValue (): int
13851451 {
13861452 return $ this ->depthValue ??= $ this ->getOwner ()->getAttribute ($ this ->depthAttribute );
13871453 }
13881454
1455+ /**
1456+ * Retrieves and caches the left boundary value of the current node.
1457+ *
1458+ * The value is cached on first access to avoid redundant lookups during nested set operations.
1459+ *
1460+ * This method is used internally by movement and update operations to determine the current node left boundary
1461+ * within the tree structure, ensuring correct calculation of node positions and validation of node movements.
1462+ *
1463+ * @return int Left boundary value of the current node as stored in the owner model.
1464+ */
13891465 private function getLeftValue (): int
13901466 {
13911467 return $ this ->leftValue ??= $ this ->getOwner ()->getAttribute ($ this ->leftAttribute );
13921468 }
13931469
13941470 /**
1395- * Returns the {@see ActiveRecord} instance to which this behavior is currently attached.
1471+ * Retrieves the owner model instance to which this behavior is attached.
13961472 *
13971473 * Ensures that the behavior has a valid owner before performing any operations that require access to the model
13981474 * instance.
@@ -1415,6 +1491,16 @@ private function getOwner(): ActiveRecord
14151491 return $ this ->owner ;
14161492 }
14171493
1494+ /**
1495+ * Retrieves and caches the right boundary value of the current node.
1496+ *
1497+ * The value is cached on first access to avoid redundant lookups during nested set operations.
1498+ *
1499+ * This method is used internally by movement and update operations to determine the current node right boundary
1500+ * within the tree structure, ensuring correct calculation of node positions and validation of node movements.
1501+ *
1502+ * @return int Right boundary value of the current node as stored in the owner model.
1503+ */
14181504 private function getRightValue (): int
14191505 {
14201506 return $ this ->rightValue ??= $ this ->getOwner ()->getAttribute ($ this ->rightAttribute );
0 commit comments