Skip to content

Commit 3f13702

Browse files
committed
feat: Improve documentation and code clarity in NestedSetsBehavior, NestedSetsQueryBehavior, NodeContext, and QueryConditionBuilder classes.
1 parent 056f106 commit 3f13702

File tree

4 files changed

+108
-20
lines changed

4 files changed

+108
-20
lines changed

src/NestedSetsBehavior.php

Lines changed: 94 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,16 @@
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);

src/NestedSetsQueryBehavior.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@
1111
/**
1212
* Behavior for {@see ActiveQuery} to support nested sets tree queries.
1313
*
14-
* Provides query methods for retrieving root and leaf nodes in a nested sets tree structure using Yii
15-
* {@see ActiveQuery}.
14+
* Provides query methods for retrieving root and leaf nodes in a nested sets tree structure using Yii Active Query.
1615
*
1716
* This behavior is designed to be attached to an {@see ActiveQuery} instance for models implementing the nested sets
1817
* pattern.

src/NodeContext.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
/**
1010
* Immutable context object containing all necessary data for node movement operations.
1111
*
12-
* Encapsulates target node, operation type, and derived values to eliminate parameter passing and provide type safety
13-
* for nested set operations.
12+
* Encapsulates target node, operation type, and derived values to remove parameter passing and provide type safety for
13+
* nested set operations.
1414
*
1515
* Key features.
1616
* - Calculated positioning values.

src/QueryConditionBuilder.php

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@
2323
* - Creates standardized condition arrays for nested sets queries.
2424
* - Enables consistent tree filtering across multiple operations.
2525
* - Handles range conditions for subtree operations.
26-
* - Supports specific node relationship queries (children, parents, siblings).
2726
* - Provides leaf node and level-based filtering conditions.
27+
* - Supports specific node relationship queries (children, parents, siblings).
2828
*
2929
* @copyright Copyright (C) 2023 Terabytesoftw.
3030
* @license https://opensource.org/license/bsd-3-clause BSD 3-Clause License.
@@ -226,11 +226,14 @@ public static function createNextSiblingCondition(
226226
*
227227
* Usage example:
228228
* ```php
229-
* $updates = QueryConditionBuilder::createOffsetUpdates($db, [
230-
* 'depth' => -1,
231-
* 'lft' => 5,
232-
* 'rgt' => 5,
233-
* ]);
229+
* $updates = QueryConditionBuilder::createOffsetUpdates(
230+
* $db,
231+
* [
232+
* 'depth' => -1,
233+
* 'lft' => 5,
234+
* 'rgt' => 5,
235+
* ],
236+
* );
234237
* // Result: [
235238
* // 'depth' => Expression('`depth` - 1'),
236239
* // 'lft' => Expression('`lft` + 5'),
@@ -485,8 +488,8 @@ public static function createSubtreeMoveCondition(
485488
/**
486489
* Creates a SQL expression for incrementing or decrementing an attribute by a specific offset.
487490
*
488-
* Generates a properly quoted SQL expression that adds or subtracts a value to an attribute, suitable for bulk
489-
* update operations in nested sets tree restructuring.
491+
* Generates a quoted SQL expression that adds or subtracts a value to an attribute, suitable for bulk update
492+
* operations in nested sets tree restructuring.
490493
*
491494
* This method ensures consistent expression formatting and proper column name quoting across different database
492495
* systems.

0 commit comments

Comments
 (0)