### 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.