### Install Package via Composer Source: https://github.com/lazychaser/laravel-nestedset/blob/v7/README.markdown Use Composer to add the kalnoy/nestedset package to your project dependencies. ```bash composer require kalnoy/nestedset ``` -------------------------------- ### Get Next and Previous Siblings Source: https://github.com/lazychaser/laravel-nestedset/blob/v7/README.markdown Fetch immediate or all subsequent siblings using `getNextSibling()` and `getNextSiblings()`. Similarly, `getPrevSibling()` and `getPrevSiblings()` retrieve preceding siblings. ```php // Get a sibling that is immediately after the node $result = $node->getNextSibling(); ``` ```php // Get all siblings that are after the node $result = $node->getNextSiblings(); ``` ```php // Get all siblings using a query $result = $node->nextSiblings()->get(); ``` ```php // Get a sibling that is immediately before the node $result = $node->getPrevSibling(); ``` ```php // Get all siblings that are before the node $result = $node->getPrevSiblings(); ``` ```php // Get all siblings using a query $result = $node->prevSiblings()->get(); ``` -------------------------------- ### Model Setup with NodeTrait Source: https://context7.com/lazychaser/laravel-nestedset/llms.txt Integrate the `NodeTrait` into your Eloquent model to enable all nested set functionalities, including tree relationships and methods. You can optionally customize the names of the `_lft`, `_rgt`, and `parent_id` columns. ```php 'Electronics']); // Node is automatically saved as a root node with _lft=1, _rgt=2 ``` -------------------------------- ### Accessing Scoped Query Builder Source: https://github.com/lazychaser/laravel-nestedset/blob/v7/README.markdown Get a scoped query builder instance from a model instance. This allows you to perform scoped operations starting from an existing node. ```php $node = MenuItem::findOrFail($id); $node->siblings()->withDepth()->get(); // OK ``` ```php $node->newScopedQuery(); ``` -------------------------------- ### Helper Methods for Node Checks Source: https://context7.com/lazychaser/laravel-nestedset/llms.txt Use boolean helper methods to check node relationships and properties like root, leaf, descendant, ancestor, child, and sibling. Also includes methods to get node bounds, height, and descendant count. ```php $node = Category::find(5); $other = Category::find(10); // Check if node is root (has no parent) $isRoot = $node->isRoot(); // Check if node is leaf (has no children) $isLeaf = $node->isLeaf(); // Check if node is descendant of another $isDescendant = $node->isDescendantOf($other); // Check if node is ancestor of another $isAncestor = $node->isAncestorOf($other); // Check if node is direct child of another $isChild = $node->isChildOf($other); // Check if nodes are siblings (same parent) $isSibling = $node->isSiblingOf($other); // Get node bounds (left and right values) [$lft, $rgt] = $node->getBounds(); // Get node height (rgt - lft + 1) $height = $node->getNodeHeight(); // Get descendant count without querying $count = $node->getDescendantCount(); // Example usage if ($node->isLeaf()) { echo "This category has no subcategories"; } elseif ($node->isRoot()) { echo "This is a top-level category with " . $node->getDescendantCount() . " items below it"; } ``` -------------------------------- ### Get Siblings Source: https://github.com/lazychaser/laravel-nestedset/blob/v7/README.markdown Retrieve siblings of a node using `getSiblings()` or the `siblings()` query builder. This includes nodes with the same parent. ```php $result = $node->getSiblings(); ``` ```php $result = $node->siblings()->get(); ``` -------------------------------- ### Get All Categories in Default Order Source: https://github.com/lazychaser/laravel-nestedset/blob/v7/README.markdown Retrieves all category nodes ordered according to the default tree structure. This is the standard way to fetch nodes when hierarchical order is important. ```php $result = Category::defaultOrder()->get(); ``` -------------------------------- ### Rebuild Subtree Source: https://github.com/lazychaser/laravel-nestedset/blob/v7/README.markdown Rebuilds a subtree starting from a specified root node. This method constrains the rebuilding process to the descendants of the given `$root` node. ```php Category::rebuildSubtree($root, $data); ``` -------------------------------- ### Retrieve Related Goods from Descendants Source: https://github.com/lazychaser/laravel-nestedset/blob/v7/README.markdown Fetch related models (e.g., 'Goods') for a category and all its descendants by first getting descendant IDs and then querying the related table. ```php // Get ids of descendants $categories = $category->descendants()->pluck('id'); ``` ```php // Include the id of category itself $categories[] = $category->getKey(); ``` ```php // Get goods $goods = Goods::whereIn('category_id', $categories)->get(); ``` -------------------------------- ### Get All Categories in Reversed Order Source: https://github.com/lazychaser/laravel-nestedset/blob/v7/README.markdown Retrieves all category nodes in the reverse of the default tree order. Useful for specific display or processing needs. ```php $result = Category::reversed()->get(); ``` -------------------------------- ### Get Subtree of a Specific Node Source: https://github.com/lazychaser/laravel-nestedset/blob/v7/README.markdown Retrieves a specific node and all its descendants, forming a subtree. `descendantsAndSelf` includes the root node in the result set. ```php $root = Category::descendantsAndSelf($rootId)->toTree()->first(); ``` -------------------------------- ### Get Subtree Excluding Root Node Source: https://github.com/lazychaser/laravel-nestedset/blob/v7/README.markdown Retrieves all descendants of a specific node, forming a subtree, but excludes the root node itself from the result. The `toTree($rootId)` method is used to build the tree structure starting from the specified ID. ```php $tree = Category::descendantsOf($rootId)->toTree($rootId); ``` -------------------------------- ### Querying Siblings in Laravel NestedSet Source: https://context7.com/lazychaser/laravel-nestedset/llms.txt Retrieve nodes that share the same parent as the current node. Includes methods for getting immediate next/previous siblings and checking sibling relationships. ```php $node = Category::find(5); // Get all siblings (excluding self) $siblings = $node->getSiblings(); // Get siblings via query builder $siblings = $node->siblings()->get(); // Get siblings and self $siblingsAndSelf = $node->getSiblingsAndSelf(); // Get next siblings (those after this node in tree order) $nextSiblings = $node->getNextSiblings(); $nextSibling = $node->getNextSibling(); // Immediate next sibling only // Get previous siblings (those before this node) $prevSiblings = $node->getPrevSiblings(); $prevSibling = $node->getPrevSibling(); // Immediate previous sibling only // Query with constraints $activeSiblings = $node->siblings()->where('active', true)->get(); // Check sibling relationship $other = Category::find(6); if ($node->isSiblingOf($other)) { echo "These nodes are siblings"; } ``` -------------------------------- ### Get Tree Error Statistics Source: https://github.com/lazychaser/laravel-nestedset/blob/v7/README.markdown Retrieves statistics about structural errors within the tree. Returns an array detailing counts of oddness, duplicates, wrong parents, and missing parents. ```php $data = Category::countErrors(); ``` -------------------------------- ### Creating Root Nodes Source: https://context7.com/lazychaser/laravel-nestedset/llms.txt Demonstrates various methods for creating root nodes, which are the top-level elements in your tree structure. This includes using `create()`, `save()`, `saveAsRoot()`, and `makeRoot()->save()`. ```php // Method 1: Using create() - automatically saved as root $root = Category::create(['name' => 'Products']); // Method 2: Using new instance and save $root = new Category(['name' => 'Services']); $root->save(); // Method 3: Convert existing node to root $existingNode = Category::find(5); $existingNode->saveAsRoot(); // Method 4: Explicit root creation with deferred save $node = new Category(['name' => 'Archive']); $node->makeRoot()->save(); // Check if node is root if ($root->isRoot()) { echo "This is a root node"; } ``` -------------------------------- ### Prepending Child Nodes Source: https://context7.com/lazychaser/laravel-nestedset/llms.txt Shows how to add a new node as the first child of an existing parent node. This can be achieved using `prependToNode()` or the parent's `prependNode()` method. The newly added node will become the first in the children list. ```php $parent = Category::find(1); // Method 1: Using deferred insert $child = new Category(['name' => 'Featured']); $child->prependToNode($parent)->save(); // Method 2: Using parent node's method (implicitly saves) $parent->prependNode(new Category(['name' => 'New Arrivals'])); // The prepended node becomes the first child $firstChild = $parent->children()->defaultOrder()->first(); echo $firstChild->name; // "New Arrivals" ``` -------------------------------- ### Prepend Node as First Child Source: https://github.com/lazychaser/laravel-nestedset/blob/v7/README.markdown To add a node as the first child of a specified parent, use the prependToNode() method followed by save(), or the parent's prependNode() method. ```php $node->prependToNode($parent)->save(); ``` ```php $parent->prependNode($node); ``` -------------------------------- ### Add Nested Set Columns (Prior Laravel) Source: https://github.com/lazychaser/laravel-nestedset/blob/v7/README.markdown Manually add the `_lft` and `_rgt` columns using `Kalnoy\Nestedset\NestedSet::columns()`. Use `dropColumns()` to remove them. ```php ... use Kalnoy\Nestedset\NestedSet; Schema::create('table', function (Blueprint $table) { ... NestedSet::columns($table); }); // To drop columns Schema::table('table', function (Blueprint $table) { NestedSet::dropColumns($table); }); ``` -------------------------------- ### Make an Existing Node a Root Source: https://github.com/lazychaser/laravel-nestedset/blob/v7/README.markdown To convert an existing node into a root node, you can either use the saveAsRoot() method for an implicit save, or call makeRoot() and then explicitly save the node. The node will be appended to the end of the root level. ```php $node->saveAsRoot(); ``` ```php $node->makeRoot()->save(); ``` -------------------------------- ### Create a New Root Node Source: https://github.com/lazychaser/laravel-nestedset/blob/v7/README.markdown To create a new node that will be a root in the tree, simply call the create method on the model or instantiate a new model and save it. This node will be appended to the end of the root level. ```php Category::create($attributes); // Saved as root ``` ```php $node = new Category($attributes); $node->save(); // Saved as root ``` -------------------------------- ### Insert Node Before or After Neighbor Source: https://github.com/lazychaser/laravel-nestedset/blob/v7/README.markdown Use `afterNode()` or `beforeNode()` for explicit saving, or `insertAfterNode()` and `insertBeforeNode()` for implicit saving. The neighbor node must exist. ```php $node->afterNode($neighbor)->save(); $node->beforeNode($neighbor)->save(); ``` ```php $node->insertAfterNode($neighbor); $node->insertBeforeNode($neighbor); ``` -------------------------------- ### Add Columns for Basic Parentage Migration Source: https://github.com/lazychaser/laravel-nestedset/blob/v7/README.markdown When migrating from a `parent_id` structure, add the `_lft` and `_rgt` unsigned integer columns to your table schema. ```php $table->unsignedInteger('_lft'); $table->unsignedInteger('_rgt'); ``` -------------------------------- ### Appending Child Nodes Source: https://context7.com/lazychaser/laravel-nestedset/llms.txt Illustrates multiple ways to add a new node as a child to an existing parent node. Methods include `appendToNode()`, `appendNode()`, using the `children()` relationship, associating via `parent()`, setting `parent_id` directly, and static `create()` with a parent. ```php $parent = Category::find(1); $child = new Category(['name' => 'Laptops']); // Method 1: Using deferred insert (recommended for control) $child->appendToNode($parent)->save(); // Method 2: Using parent node's method (implicitly saves) $parent->appendNode(new Category(['name' => 'Phones'])); // Method 3: Using children relationship $parent->children()->create(['name' => 'Tablets']); // Method 4: Using parent relationship $child = new Category(['name' => 'Cameras']); $child->parent()->associate($parent)->save(); // Method 5: Setting parent_id directly $child = new Category(['name' => 'TVs']); $child->parent_id = $parent->id; $child->save(); // Method 6: Using static create with parent Category::create(['name' => 'Audio'], $parent); // Check if node actually moved after save if ($child->save() && $child->hasMoved()) { echo "Node was moved to new position"; } ``` -------------------------------- ### Build Tree from Array Source: https://github.com/lazychaser/laravel-nestedset/blob/v7/README.markdown The `create` static method recursively builds a tree if the attributes contain a 'children' key. The `$node->children` property will contain the created child nodes. ```php $node = Category::create([ 'name' => 'Foo', 'children' => [ [ 'name' => 'Bar', 'children' => [ [ 'name' => 'Baz' ], ], ], ], ]); ``` -------------------------------- ### Eager Load Ancestors with Pagination Source: https://github.com/lazychaser/laravel-nestedset/blob/v7/README.markdown Eager load ancestors using `with('ancestors')` for efficient retrieval, especially when paginating results. This is useful for displaying breadcrumbs in views. ```php $categories = Category::with('ancestors')->paginate(30); ``` ```html @foreach($categories as $i => $category) {{ $category->ancestors->count() ? implode(' > ', $category->ancestors->pluck('name')->toArray()) : 'Top Level' }}
{{ $category->name }} @endforeach ``` -------------------------------- ### Query Ancestors and Descendants Source: https://github.com/lazychaser/laravel-nestedset/blob/v7/README.markdown Use static methods like `ancestorsOf`, `ancestorsAndSelf`, `descendantsOf`, and `descendantsAndSelf` to retrieve specific node sets. The `defaultOrder()` scope can be applied for ordered results. ```php $result = Category::ancestorsOf($id); $result = Category::ancestorsAndSelf($id); $result = Category::descendantsOf($id); $result = Category::descendantsAndSelf($id); ``` ```php $result = Category::defaultOrder()->ancestorsOf($id); ``` -------------------------------- ### Build Flat Tree Structure Source: https://github.com/lazychaser/laravel-nestedset/blob/v7/README.markdown Converts a collection of nodes into a flat list where child nodes appear immediately after their parent. Useful for custom ordering without recursion. ```php $nodes = Category::get()->toFlatTree(); ``` -------------------------------- ### Build Full Tree Structure Source: https://github.com/lazychaser/laravel-nestedset/blob/v7/README.markdown Converts a collection of nodes into a hierarchical tree structure, populating `parent` and `children` relationships. This is typically used before rendering a nested view. ```php $tree = Category::get()->toTree(); ``` -------------------------------- ### Include Node Depth Source: https://github.com/lazychaser/laravel-nestedset/blob/v7/README.markdown Use `withDepth()` to include the depth level of each node in the query results. The root node is at level 0, and its children are at level 1. ```php $result = Category::withDepth()->find($id); $depth = $result->depth; ``` -------------------------------- ### Build Tree from Array Source: https://context7.com/lazychaser/laravel-nestedset/llms.txt Create entire tree structures at once using nested array data with the 'children' key. After creation, you can access and iterate through the children and their counts. ```php // Create a complete tree structure from nested array $tree = Category::create([ 'name' => 'Electronics', 'children' => [ [ 'name' => 'Computers', 'children' => [ ['name' => 'Laptops'], ['name' => 'Desktops'], ['name' => 'Tablets'], ], ], [ 'name' => 'Phones', 'children' => [ ['name' => 'Smartphones'], ['name' => 'Feature Phones'], ], ], [ 'name' => 'Accessories', ], ], ]); // Access the created children foreach ($tree->children as $child) { echo $child->name . " has " . $child->children->count() . " children\n"; } // Output: // Computers has 3 children // Phones has 2 children // Accessories has 0 children ``` -------------------------------- ### Migrate from Parent ID to Nested Set Structure Source: https://context7.com/lazychaser/laravel-nestedset/llms.txt Add `_lft` and `_rgt` columns to your table using a migration, then call `Category::fixTree()` to populate these columns based on existing `parent_id` relationships. If migrating from a different nested set package, override column name methods like `getLftName()`. ```php // Step 1: Add nested set columns to existing table Schema::table('categories', function (Blueprint $table) { $table->unsignedInteger('_lft')->default(0); $table->unsignedInteger('_rgt')->default(0); // parent_id should already exist }); ``` ```php // Step 2: Run fixTree to populate _lft and _rgt based on parent_id // This will calculate proper nested set values from parent relationships Category::fixTree(); ``` ```php // Migrating from another nested set package with different columns class Category extends Model { use NodeTrait; // Override column names to match existing schema public function getLftName() { return 'left'; // Your existing left column name } public function getRgtName() { return 'right'; // Your existing right column name } public function getParentIdName() { return 'parent'; // Your existing parent id column name } // Add mutator for parent attribute if using non-standard name public function setParentAttribute($value) { $this->setParentIdAttribute($value); } } ``` -------------------------------- ### Insert Node Before or After Sibling Source: https://context7.com/lazychaser/laravel-nestedset/llms.txt Position a node relative to another node at the same tree level. Use `afterNode()` or `beforeNode()` for deferred saving, or `insertAfterNode()` / `insertBeforeNode()` for immediate saving. Existing nodes can also be moved relative to siblings. ```php $existingNode = Category::where('name', 'Phones')->first(); // Insert after a sibling (deferred - requires save) $newNode = new Category(['name' => 'Accessories']); $newNode->afterNode($existingNode)->save(); // Insert before a sibling (deferred - requires save) $anotherNode = new Category(['name' => 'Cases']); $anotherNode->beforeNode($existingNode)->save(); // Insert with implicit save $immediateNode = new Category(['name' => 'Chargers']); $immediateNode->insertAfterNode($existingNode); $anotherImmediate = new Category(['name' => 'Cables']); $anotherImmediate->insertBeforeNode($existingNode); // Move existing node relative to another $nodeToMove = Category::find(10); $targetSibling = Category::find(5); $nodeToMove->afterNode($targetSibling)->save(); ``` -------------------------------- ### Converting Flat Collections to Tree Structure Source: https://context7.com/lazychaser/laravel-nestedset/llms.txt Transform a flat collection of nodes into a hierarchical tree with parent-children relationships. Supports rendering, extracting subtrees, and creating flat tree representations. ```php // Convert flat collection to nested tree $tree = Category::get()->toTree(); ``` ```php // Render tree recursively $renderTree = function ($nodes, $prefix = '') use (&$renderTree) { foreach ($nodes as $node) { echo $prefix . '- ' . $node->name . "\n"; if ($node->children->isNotEmpty()) { $renderTree($node->children, $prefix . ' '); } } }; $renderTree($tree); ``` ```php // Get only a specific subtree $rootId = 1; $subtree = Category::descendantsAndSelf($rootId)->toTree()->first(); ``` ```php // Get subtree without root node itself $subtree = Category::descendantsOf($rootId)->toTree($rootId); ``` ```php // Convert to flat tree (maintains parent-child order without nesting) $flatTree = Category::get()->toFlatTree(); foreach ($flatTree as $node) { echo $node->name . "\n"; } ``` -------------------------------- ### Access Parent Relationship Source: https://context7.com/lazychaser/laravel-nestedset/llms.txt Retrieve the immediate parent of a node using the `parent` relationship. Eager loading with `with('parent')` is recommended to avoid N+1 query issues. The `isChildOf()` method checks for a direct parent-child relationship. ```php $node = Category::find(5); // Access parent directly (may trigger query if not loaded) $parent = $node->parent; if ($parent) { echo "Parent: " . $parent->name; } else { echo "This is a root node"; } // Eager load parent to avoid N+1 queries $categories = Category::with('parent')->get(); foreach ($categories as $category) { $parentName = $category->parent ? $category->parent->name : 'Root'; echo "{$category->name} -> {$parentName}\n"; } // Check parent relationship $other = Category::find(10); if ($node->isChildOf($other)) { echo "{$node->name} is a direct child of {$other->name}"; } ``` -------------------------------- ### Rebuild Tree from Array Source: https://github.com/lazychaser/laravel-nestedset/blob/v7/README.markdown Use `rebuildTree` for mass-changing the tree structure. Provide an array of nodes; existing nodes with matching IDs are updated, new nodes are created. The `$delete` parameter controls whether nodes not present in the data are removed. ```php Category::rebuildTree($data, $delete); ``` ```php $data = [ [ 'id' => 1, 'name' => 'foo', 'children' => [ ... ] ], [ 'name' => 'bar' ], ]; ``` -------------------------------- ### Check Node Relationships Source: https://github.com/lazychaser/laravel-nestedset/blob/v7/README.markdown Provides helper methods to check various relationships of a node, such as being a child, ancestor, sibling, or leaf node. ```php $node->isChildOf($other); ``` ```php $node->isAncestorOf($other); ``` ```php $node->isSiblingOf($other); ``` ```php $node->isLeaf() ``` -------------------------------- ### Access Children Relationship Source: https://context7.com/lazychaser/laravel-nestedset/llms.txt Retrieve all immediate children of a node using the `children` relationship. The `children->count()` method provides the number of direct children. `isLeaf()` efficiently checks if a node has any children without an additional query. ```php $parent = Category::find(1); // Access children (lazy loaded) $children = $parent->children; echo "Children count: " . $children->count() . "\n"; foreach ($children as $child) { echo "- " . $child->name . "\n"; } // Eager load children $categories = Category::with('children')->whereIsRoot()->get(); // Check if node has children if ($parent->children->isNotEmpty()) { echo "Has children"; } // Check using isLeaf (more efficient - no extra query) if (!$parent->isLeaf()) { echo "Has children (is not a leaf node)"; } // Get children with additional constraints $activeChildren = $parent->children()->where('active', true)->get(); ``` -------------------------------- ### Add Nested Set Columns (Laravel 5.5+) Source: https://github.com/lazychaser/laravel-nestedset/blob/v7/README.markdown Use the `nestedSet()` schema builder method to add the required `_lft` and `_rgt` columns to your table. Use `dropNestedSet()` to remove them. ```php Schema::create('table', function (Blueprint $table) { ... $table->nestedSet(); }); // To drop columns Schema::table('table', function (Blueprint $table) { $table->dropNestedSet(); }); ``` -------------------------------- ### Eager Loading with Scopes Source: https://github.com/lazychaser/laravel-nestedset/blob/v7/README.markdown When eager loading relationships like descendants, always use the `scoped` method to ensure the loading is performed within the correct scope. Failing to do so can lead to incorrect results. ```php MenuItem::scoped([ 'menu_id' => 5])->with('descendants')->findOrFail($id); // OK MenuItem::with('descendants')->findOrFail($id); // WRONG ``` -------------------------------- ### Access Ancestors and Descendants Source: https://github.com/lazychaser/laravel-nestedset/blob/v7/README.markdown Access the `ancestors` and `descendants` properties for eager loading or direct access. These collections represent the parent chain and all sub-tree nodes, respectively. ```php // Accessing ancestors $node->ancestors; ``` ```php // Accessing descendants $node->descendants; ``` -------------------------------- ### Fix Tree After Migrating Parent IDs Source: https://github.com/lazychaser/laravel-nestedset/blob/v7/README.markdown After adding the `_lft` and `_rgt` columns and setting up the model with `NodeTrait`, call `fixTree()` to populate these columns based on existing `parent_id` data. ```php MyModel::fixTree(); ``` -------------------------------- ### Render Tree Recursively Source: https://github.com/lazychaser/laravel-nestedset/blob/v7/README.markdown A recursive function to traverse and display a tree structure. It iterates through nodes and their children, applying a prefix for indentation. ```php $nodes = Category::get()->toTree(); $traverse = function ($categories, $prefix = '-') use (&$traverse) { foreach ($categories as $category) { echo PHP_EOL.$prefix.' '.$category->name; $traverse($category->children, $prefix.'-'); } }; $traverse($nodes); ``` -------------------------------- ### Use NodeTrait in Model Source: https://github.com/lazychaser/laravel-nestedset/blob/v7/README.markdown Include the `Kalnoy\Nestedset\NodeTrait` trait in your Eloquent model to enable nested set functionality. ```php use Kalnoy\Nestedset\NodeTrait; class Foo extends Model { use NodeTrait; } ``` -------------------------------- ### Database Migration for Nested Set Columns Source: https://context7.com/lazychaser/laravel-nestedset/llms.txt Define a database migration to create a table with the necessary columns for the nested set model. The `nestedSet()` method automatically adds `_lft`, `_rgt`, and `parent_id` columns. For older Laravel versions, `NestedSet::columns($table)` can be used. ```php // Migration for Laravel 5.5+ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class CreateCategoriesTable extends Migration { public function up() { Schema::create('categories', function (Blueprint $table) { $table->id(); $table->string('name'); $table->nestedSet(); // Adds _lft, _rgt, parent_id columns $table->timestamps(); }); } public function down() { Schema::table('categories', function (Blueprint $table) { $table->dropNestedSet(); }); Schema::dropIfExists('categories'); } } ``` ```php // For Laravel versions prior to 5.5 use Kalnoy\Nestedset\NestedSet; Schema::create('categories', function (Blueprint $table) { $table->id(); $table->string('name'); NestedSet::columns($table); // Manually add nested set columns $table->timestamps(); }); ``` -------------------------------- ### Querying Tree Nodes Source: https://context7.com/lazychaser/laravel-nestedset/llms.txt Filter nodes using tree-specific constraints like roots, leaves, and positional relationships. Supports descendant and ancestor queries with OR logic and exclusion. ```php // Get only root nodes $roots = Category::whereIsRoot()->get(); ``` ```php // Get only leaf nodes (nodes without children) $leaves = Category::whereIsLeaf()->get(); // Or use the shorthand $leaves = Category::leaves(); ``` ```php // Get non-root nodes (nodes with parent) $nonRoots = Category::hasParent()->get(); ``` ```php // Get non-leaf nodes (nodes with children) $parents = Category::hasChildren()->get(); ``` ```php // Get nodes after a specific node (by tree position) $afterNode = Category::whereIsAfter($nodeId)->get(); ``` ```php // Get nodes before a specific node $beforeNode = Category::whereIsBefore($nodeId)->get(); ``` ```php // Descendant constraints with OR logic $result = Category::whereDescendantOf($node1) ->orWhereDescendantOf($node2) ->get(); ``` ```php // Exclude descendants of a node $result = Category::whereNotDescendantOf($excludedNode)->get(); ``` ```php // Ancestor constraints $ancestorsOf = Category::whereAncestorOf($node)->get(); $ancestorsOrSelf = Category::whereAncestorOrSelf($nodeId)->get(); ``` ```php // Combine multiple constraints $filtered = Category::whereIsLeaf() ->whereDescendantOf($rootId) ->where('active', true) ->defaultOrder() ->get(); ``` -------------------------------- ### Querying Scoped Nodes Source: https://github.com/lazychaser/laravel-nestedset/blob/v7/README.markdown When using scopes, always use the `scoped` method to apply the scope criteria. This ensures queries only affect nodes within the specified scope, such as a particular `menu_id`. ```php MenuItem::scoped([ 'menu_id' => 5 ])->withDepth()->get(); // OK MenuItem::descendantsOf($id)->get(); // WRONG: returns nodes from other scope MenuItem::scoped([ 'menu_id' => 5 ])->fixTree(); // OK ``` -------------------------------- ### Retrieve Nodes by Depth Source: https://github.com/lazychaser/laravel-nestedset/blob/v7/README.markdown Filter nodes by their depth level using the `having('depth', '=', level)` constraint after enabling `withDepth()`. Note: This may not work in database strict mode. ```php $result = Category::withDepth()->having('depth', '=', 1)->get(); ``` -------------------------------- ### Override Column Names for Migration Source: https://github.com/lazychaser/laravel-nestedset/blob/v7/README.markdown If your existing columns for left, right, or parent ID have different names, override these methods in your model to match your schema. ```php public function getLftName() { return 'left'; } public function getRgtName() { return 'right'; } public function getParentIdName() { return 'parent'; } // Specify parent id attribute mutator public function setParentAttribute($value) { $this->setParentIdAttribute($value); } ``` -------------------------------- ### Check Tree Consistency Source: https://github.com/lazychaser/laravel-nestedset/blob/v7/README.markdown Checks if the entire tree structure has any structural errors. Returns a boolean value indicating whether the tree is broken. ```php $bool = Category::isBroken(); ``` -------------------------------- ### Querying Ancestors in Laravel NestedSet Source: https://context7.com/lazychaser/laravel-nestedset/llms.txt Retrieve all parent nodes up to the root. Useful for breadcrumbs and path display. Use `with('ancestors')` for eager loading. ```php $node = Category::find(10); // Access ancestors via relationship (lazy loaded) $ancestors = $node->ancestors; // Query ancestors with ordering (important for correct path) $ancestors = Category::defaultOrder()->ancestorsOf($node->id); // Include the node itself $pathWithSelf = Category::ancestorsAndSelf($node->id); // Eager load ancestors for multiple nodes (great for breadcrumbs) $categories = Category::with('ancestors')->paginate(20); foreach ($categories as $category) { if ($category->ancestors->count()) { $breadcrumb = $category->ancestors->pluck('name')->implode(' > '); echo $breadcrumb . ' > ' . $category->name . "\n"; } else { echo $category->name . " (Top Level)\n"; } } // Check ancestor relationship $possibleAncestor = Category::find(1); if ($node->isDescendantOf($possibleAncestor)) { echo "{$node->name} is under {$possibleAncestor->name}"; } ``` -------------------------------- ### Default Tree Ordering in Laravel NestedSet Source: https://context7.com/lazychaser/laravel-nestedset/llms.txt Apply hierarchical ordering to query results using left values for proper tree traversal. Includes methods for moving nodes up/down within siblings. ```php // Get all categories in tree order $orderedCategories = Category::defaultOrder()->get(); // Reverse tree order $reversed = Category::reversed()->get(); // Combine with other constraints $orderedDescendants = Category::descendantsOf($rootId) ->defaultOrder() ->get(); // Move node within siblings (affects default order) $node = Category::find(5); // Move up by one position $node->up(); // Move down by one position $node->down(); // Move up by multiple positions $node->up(3); // Check if position changed if ($node->down()) { echo "Node moved down successfully"; } else { echo "Node is already at the bottom"; } ``` -------------------------------- ### Fix Tree Structure Source: https://github.com/lazychaser/laravel-nestedset/blob/v7/README.markdown Call this static method to repair and re-index the `_lft` and `_rgt` values of all nodes in the tree based on the `parent_id` column. ```php Node::fixTree(); ``` -------------------------------- ### Filter Nodes by Descendant Relationship Source: https://github.com/lazychaser/laravel-nestedset/blob/v7/README.markdown Queries for nodes that are descendants of a specified node. The `$node` can be a model instance or a primary key. Use `orWhereDescendantOf` for OR conditions. ```php $result = Category::whereDescendantOf($node)->get(); ``` ```php $result = Category::whereNotDescendantOf($node)->get(); ``` ```php $result = Category::orWhereDescendantOf($node)->get(); ``` ```php $result = Category::orWhereNotDescendantOf($node)->get(); ``` ```php $result = Category::whereDescendantAndSelf($id)->get(); ``` ```php $result = Category::whereDescendantOrSelf($node)->get(); ``` -------------------------------- ### Check and Fix Tree Consistency in Laravel NestedSet Source: https://context7.com/lazychaser/laravel-nestedset/llms.txt Use `isBroken()` to detect structural errors and `fixTree()` or `fixSubtree()` to repair them. `countErrors()` provides detailed statistics on different types of inconsistencies. ```php // Check if tree has any errors if (Category::isBroken()) { echo "Tree structure is corrupted!"; } ``` ```php // Get detailed error statistics $errors = Category::countErrors(); /* Returns array with keys: - oddness: nodes with invalid lft/rgt relationship - duplicates: nodes with duplicate lft or rgt values - wrong_parent: nodes where parent_id doesn't match lft/rgt bounds - missing_parent: nodes with parent_id pointing to non-existent node */ echo "Oddness errors: " . $errors['oddness'] . "\n"; echo "Duplicate errors: " . $errors['duplicates'] . "\n"; echo "Wrong parent errors: " . $errors['wrong_parent'] . "\n"; echo "Missing parent errors: " . $errors['missing_parent'] . "\n"; ``` ```php // Fix the entire tree based on parent_id relationships $fixedCount = Category::fixTree(); echo "Fixed {" . $fixedCount . "} nodes"; ``` ```php // Fix only a subtree under specific root $root = Category::find(1); $fixedCount = Category::fixSubtree($root); ``` -------------------------------- ### Append Node as Last Child Source: https://github.com/lazychaser/laravel-nestedset/blob/v7/README.markdown To add a node as the last child of a specified parent, you can use the appendToNode() method followed by save(), or the parent's appendNode() method. Alternatively, you can use the parent's children relationship to create the node directly. ```php $node->appendToNode($parent)->save(); ``` ```php $parent->appendNode($node); ``` ```php $parent->children()->create($attributes); ``` ```php $node->parent()->associate($parent)->save(); ``` ```php $node->parent_id = $parent->id; $node->save(); ``` ```php Category::create($attributes, $parent); ``` -------------------------------- ### Filter Nodes by Ancestor Relationship Source: https://github.com/lazychaser/laravel-nestedset/blob/v7/README.markdown Queries for nodes that are ancestors of a specified node. The `$node` can be a model instance or a primary key. `whereAncestorOrSelf` includes the node itself in the results. ```php $result = Category::whereAncestorOf($node)->get(); ``` ```php $result = Category::whereAncestorOrSelf($id)->get(); ``` -------------------------------- ### Define Scope Attributes Source: https://github.com/lazychaser/laravel-nestedset/blob/v7/README.markdown Override this method in your model to specify attributes that should be used for scoping. This is useful when you have multiple trees within the same table, distinguished by a foreign key. ```php protected function getScopeAttributes() { return [ 'menu_id' ]; } ``` -------------------------------- ### Shift Node Position Source: https://github.com/lazychaser/laravel-nestedset/blob/v7/README.markdown Moves a node up or down within its parent's children list to alter its position in the default order. Accepts an optional integer to shift by multiple positions. ```php $bool = $node->down(); ``` ```php $bool = $node->up(); ``` ```php $bool = $node->down(3); ``` -------------------------------- ### Deleting Nodes from Tree Source: https://context7.com/lazychaser/laravel-nestedset/llms.txt Remove nodes from the tree, automatically handling descendants. Emphasizes using model deletion over query builder to prevent tree corruption. Supports soft deletes and force deletes. ```php $node = Category::find(5); // Delete node and all its descendants $node->delete(); // IMPORTANT: Always delete via model, never via query builder // This is WRONG and will corrupt the tree: // Category::where('id', 5)->delete(); // DON'T DO THIS! // With SoftDeletes trait, descendants are also soft deleted // When restoring, descendants deleted at the same time are also restored // Force delete with SoftDeletes $node->forceDelete(); // Safe pattern with transaction DB::transaction(function () { $node = Category::find(5); $node->delete(); }); ``` -------------------------------- ### Including Node Depth in Laravel NestedSet Queries Source: https://context7.com/lazychaser/laravel-nestedset/llms.txt Add the depth level of each node in query results for hierarchical display. Root nodes are at depth 0. Can be combined with other query constraints. ```php // Include depth in results (root = 0, children = 1, etc.) $categories = Category::withDepth()->get(); foreach ($categories as $category) { $indent = str_repeat(' ', $category->depth); echo $indent . $category->name . " (level {" . $category->depth . "})\n"; } // Filter by specific depth level // Note: This uses HAVING clause and won't work in strict mode $secondLevel = Category::withDepth() ->having('depth', '=', 1) ->get(); // Combine with other queries $result = Category::withDepth() ->whereDescendantOf($rootId) ->defaultOrder() ->get(); ``` -------------------------------- ### Querying Descendants in Laravel NestedSet Source: https://context7.com/lazychaser/laravel-nestedset/llms.txt Retrieve all child nodes recursively, including children of children to any depth. Use `with('descendants')` for eager loading. Efficiently count descendants using `getDescendantCount()`. ```php $root = Category::find(1); // Access descendants via relationship $allDescendants = $root->descendants; echo "Total descendants: " . $allDescendants->count(); // Using query methods $descendants = Category::descendantsOf($root->id); $descendantsWithSelf = Category::descendantsAndSelf($root->id); // With query constraints $activeDescendants = Category::whereDescendantOf($root) ->where('active', true) ->get(); // Eager loading descendants $roots = Category::with('descendants')->whereIsRoot()->get(); // Get all related items from another table for a category and its descendants $categoryIds = $root->descendants()->pluck('id'); $categoryIds[] = $root->id; $products = Product::whereIn('category_id', $categoryIds)->get(); // Count descendants efficiently (no extra query) $descendantCount = $root->getDescendantCount(); ``` -------------------------------- ### Define Scoping for Multiple Trees in Laravel NestedSet Source: https://context7.com/lazychaser/laravel-nestedset/llms.txt Implement `getScopeAttributes()` in your model to define attributes that separate multiple independent trees within the same table. Use `scoped()` for queries when the scope is not set on the model instance. ```php 1])->get(); $menu2Items = MenuItem::scoped(['menu_id' => 2])->get(); ``` ```php // Correct: Using scoped query MenuItem::scoped(['menu_id' => 1])->withDepth()->get(); // OK MenuItem::scoped(['menu_id' => 1])->fixTree(); // OK // WRONG: These will mix items from different menus // MenuItem::descendantsOf($id)->get(); // DON'T DO THIS ``` ```php // When using model instance, scope is applied automatically $item = MenuItem::find($id); $siblings = $item->siblings()->get(); // Automatically scoped ``` ```php // Get scoped query from instance $scopedQuery = $item->newScopedQuery(); ``` ```php // Eager loading with scoped queries $items = MenuItem::scoped(['menu_id' => 1]) ->with('descendants') ->find($id); // OK ``` ```php // Building a scoped tree $tree = MenuItem::scoped(['menu_id' => 1]) ->defaultOrder() ->get() ->toTree(); ``` -------------------------------- ### Check if Node is Root Source: https://github.com/lazychaser/laravel-nestedset/blob/v7/README.markdown Verifies if a node is a root node in the tree structure. Returns a boolean value. ```php $bool = $node->isRoot(); ``` -------------------------------- ### Delete a Node Source: https://github.com/lazychaser/laravel-nestedset/blob/v7/README.markdown Deletes a single node. Important: This operation will also delete all descendants of the node. Avoid using mass delete queries like `Category::where('id', '=', $id)->delete();` as this will break the tree structure. ```php $node->delete(); ``` -------------------------------- ### Check if Node Moved After Save Source: https://github.com/lazychaser/laravel-nestedset/blob/v7/README.markdown After saving a node, check if its position in the tree has changed using the hasMoved() method. This is useful if your application logic depends on whether a structural manipulation occurred. ```php if ($node->save()) { $moved = $node->hasMoved(); } ``` -------------------------------- ### Check if Node is Descendant Source: https://github.com/lazychaser/laravel-nestedset/blob/v7/README.markdown Determines if a node is a descendant of another specified node. Returns a boolean value. ```php $bool = $node->isDescendantOf($parent); ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.