Baum
Baum is an implementation of the Nested Set pattern for Laravel's Eloquent ORM.
Install / Use
/learn @etrepat/BaumREADME
Baum
Baum is an implementation of the Nested Set pattern for Laravel 5's Eloquent ORM.
For Laravel 4.2.x compatibility, check the 1.0.x branch branch or use the latest 1.0.x tagged release.
Documentation
- About Nested Sets
- The theory behind, a TL;DR version
- Installation
- Getting started
- Usage
- Further information
- Contributing
<a name="about"></a>
About Nested Sets
A nested set is a smart way to implement an ordered tree that allows for fast, non-recursive queries. For example, you can fetch all descendants of a node in a single query, no matter how deep the tree. The drawback is that insertions/moves/deletes require complex SQL, but that is handled behind the curtains by this package!
Nested sets are appropriate for ordered trees (e.g. menus, commercial categories) and big trees that must be queried efficiently (e.g. threaded posts).
See the wikipedia entry for nested sets for more info. Also, this is a good introductory tutorial: http://www.evanpetersen.com/item/nested-sets.html
<a name="theory"></a>
The theory behind, a TL;DR version
An easy way to visualize how a nested set works is to think of a parent entity surrounding all of its children, and its parent surrounding it, etc. So this tree:
root
|_ Child 1
|_ Child 1.1
|_ Child 1.2
|_ Child 2
|_ Child 2.1
|_ Child 2.2
Could be visualized like this:
___________________________________________________________________
| Root |
| ____________________________ ____________________________ |
| | Child 1 | | Child 2 | |
| | __________ _________ | | __________ _________ | |
| | | C 1.1 | | C 1.2 | | | | C 2.1 | | C 2.2 | | |
1 2 3_________4 5________6 7 8 9_________10 11_______12 13 14
| |___________________________| |___________________________| |
|___________________________________________________________________|
The numbers represent the left and right boundaries. The table then might look like this:
id | parent_id | lft | rgt | depth | data
1 | | 1 | 14 | 0 | root
2 | 1 | 2 | 7 | 1 | Child 1
3 | 2 | 3 | 4 | 2 | Child 1.1
4 | 2 | 5 | 6 | 2 | Child 1.2
5 | 1 | 8 | 13 | 1 | Child 2
6 | 5 | 9 | 10 | 2 | Child 2.1
7 | 5 | 11 | 12 | 2 | Child 2.2
To get all children of a parent node, you
SELECT * WHERE lft IS BETWEEN parent.lft AND parent.rgt
To get the number of children, it's
(right - left - 1)/2
To get a node and all its ancestors going back to the root, you
SELECT * WHERE node.lft IS BETWEEN lft AND rgt
As you can see, queries that would be recursive and prohibitively slow on ordinary trees are suddenly quite fast. Nifty, isn't it?
<a name="installation"></a>
Installation
Baum works with Laravel 5 onwards. You can add it to your composer.json file
with:
"baum/baum": "~1.1"
Run composer install to install it.
As with most Laravel 5 packages you'll then need to register the Baum
service provider. To do that, head over your config/app.php file and add
the following line into the providers array:
'Baum\Providers\BaumServiceProvider',
<a name="getting-started"></a>
Getting started
After the package is correctly installed the easiest way to get started is to run the provided generator:
php artisan baum:install MODEL
Replace model by the class name you plan to use for your Nested Set model.
The generator will install a migration and a model file into your application configured to work with the Nested Set behaviour provided by Baum. You SHOULD take a look at those files, as each of them describes how they can be customized.
Next, you would probably run artisan migrate to apply the migration.
Model configuration
In order to work with Baum, you must ensure that your model class extends
Baum\Node.
This is the easiest it can get:
class Category extends Baum\Node {
}
This is a slightly more complex example where we have the column names customized:
class Dictionary extends Baum\Node {
protected $table = 'dictionary';
// 'parent_id' column name
protected $parentColumn = 'parent_id';
// 'lft' column name
protected $leftColumn = 'lidx';
// 'rgt' column name
protected $rightColumn = 'ridx';
// 'depth' column name
protected $depthColumn = 'nesting';
// guard attributes from mass-assignment
protected $guarded = array('id', 'parent_id', 'lidx', 'ridx', 'nesting');
}
Remember that, obviously, the column names must match those in the database table.
Migration configuration
You must ensure that the database table that supports your Baum models has the following columns:
parent_id: a reference to the parent (int)lft: left index bound (int)rgt: right index bound (int)depth: depth or nesting level (int)
Here is a sample migration file:
class Category extends Migration {
public function up() {
Schema::create('categories', function(Blueprint $table) {
$table->increments('id');
$table->integer('parent_id')->nullable();
$table->integer('lft')->nullable();
$table->integer('rgt')->nullable();
$table->integer('depth')->nullable();
$table->string('name', 255);
$table->timestamps();
});
}
public function down() {
Schema::drop('categories');
}
}
You may freely modify the column names, provided you change them both in the migration and the model.
<a name="usage"></a>
Usage
After you've configured your model and run the migration, you are now ready to use Baum with your model. Below are some examples.
- Creating a root node
- Inserting nodes
- Deleting nodes
- Getting the nesting level of a node
- Moving nodes around
- Asking questions to your nodes
- Relations
- Root and Leaf scopes
- Accessing the ancestry/descendancy chain
- Limiting levels of children returned
- Custom sorting column
- Dumping the hierarchy tree
- Model events:
movingandmoved - Scope support
- Validation
- Tree rebuilding
- Soft deletes
- Seeding/Mass assignment
- Misc/Utility functions
<a name="creating-root-node"></a>
Creating a root node
By default, all nodes are created as roots:
$root = Category::create(['name' => 'Root category']);
Alternatively, you may find yourself in the need of converting an existing node into a root node:
$node->makeRoot();
You may also nullify it's parent_id column to accomplish the same behaviour:
// This works the same as makeRoot()
$node->parent_id = null;
$node->save();
<a name="inserting-nodes"></a>
Inserting nodes
// Directly with a relation
$child1 = $root->children()->create(['name' => 'Child 1']);
// with the `makeChildOf` method
$child2 = Category::create(['name' => 'Child 2']);
$child2->makeChildOf($root);
<a name="deleting-nodes"></a>
Deleting nodes
$child1->delete();
Descendants of deleted nodes will also be deleted and all the lft and rgt
bound will be recalculated. Pleases note that, for now, deleting and deleted
model events for the descendants will not be fired.
<a name="node-level"></a>
Getting the nesting level of a node
The getLevel() method will return current nesting level, or depth, of a node.
$node->getLevel() // 0 when root
<a name="moving-nodes"></a>
Moving nodes around
Baum provides several methods for moving nodes around:
moveLeft(): Find the left sibling and move to the left of it.moveRight(): Find the right sibling and move to the right of it.moveToLeftOf($otherNode): Move to the node to the left of ...moveToRightOf($otherNode): Move to the node to the right of ...makeNextSiblingOf($otherNode): Alias formoveToRightOf.makeSiblingOf($otherNode): Alias formakeNextSiblingOf.makePreviousSiblingOf($otherNode): Alias formoveToLeftOf.makeChildOf($otherNode): Make the node a child of ...makeFirstChildOf($otherNode): Make the node the first child of ...makeLastChildOf($otherNode): Alias formakeChildOf.makeRoot(): Make current node a root node.
For example:
$root = Creatures::create(['name' => 'The Root of All Evil']);
$dragons = Creatures::create(['name' => 'Here Be Dragons']);
$dragons->makeChildOf($root);
$monsters = new Creatures(['name' => 'Horrible Monsters']);
$monsters->save();
$monsters->makeSiblingOf($dragons);
$demons = Creatures::where('name', '=', 'demons')->first();
$demons->moveToLeftOf($dragons);
<a name="node-questions"></a>
Asking questions to your nodes
You can ask some questions to your Baum nodes:
isRoot(): Returns true if this is a root node.isLeaf(): Returns true if this is a leaf node (end of a branch).isChild(): Returns true if this is a child node.isDescendantOf($other): Returns true if no
Related Skills
node-connect
352.2kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
111.1kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
352.2kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
352.2kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。

