Laravel-nestedset is a relational database traversal tree larvel4-5 plug-in package, the main and we share the Laravel-nestedset multi-level unlimited classification, hope to help everyone.
Directory:
Nested Sets Model Introduction
The Nested Set Model is a clever way to implement an ordered tree, which is fast and does not require recursive queries, for example, regardless of how many layers the tree has, you can use only one query to get all the descendants under a node, the disadvantage is that its insert, move, delete need to execute complex SQL statements, But these are processed within this plugin!
More details on Wikipedia! Nested set model and its Chinese translation! Nested collection Models
Installation Requirements
php>=5.4
laravel>=4.1
Support for Laravel-5.5 after v4.3 version
V4 version supports Laravel-5.2, 5.3, 5.4
V3 Version Support Laravel-5.1
V2 Version Support Laravel-4
It is strongly recommended to use a data engine that supports the things feature (like MySQL's InnoDB) to prevent possible data corruption.
Installation
composer.jsonAdd the following code to the file:
"Kalnoy/nestedset": "^4.3",
Run composer install to install it.
or enter it directly at the command line
Composer require Kalnoy/nestedset
To install the historical version please click More versions
Start using
Migrating files
You can use NestedSet the method of the class columns to add a field with a default name:
... use kalnoy\nestedset\nestedset; Schema::create (' table ', function (Blueprint $table) { ... Nestedset::columns ($table);});
To delete a field:
... use kalnoy\nestedset\nestedset; schema::table (' table ', function (Blueprint $table) { nestedset::d ropcolumns ($table);});
The default field name is:,, _lft _rgt parent_id , the source code is as follows:
public static function columns (Blueprint $table) { $table->unsignedinteger (self::lft)->default (0); $table->unsignedinteger (SELF::RGT)->default (0); $table->unsignedinteger (self::P arent_id)->nullable (); $table->index (Static::getdefaultcolumns ()); }
Model
Your model needs to use Kalnoy\Nestedset\NodeTrait trait to implement nested sets
Use Kalnoy\nestedset\nodetrait;class Foo extends Model {use nodetrait;}
Migrating data that is already in place elsewhere
Migrating from other nested set model libraries
Public Function Getlftname () { return ' left ';} Public Function Getrgtname () { return ' right ';} Public Function Getparentidname () { return ' parent ';} Specify Parent id attribute mutatorpublic function setparentattribute ($value) { $this->setparentidattribute ( $value);}
Migrating from other model libraries with parent-child relationships
If your database tree contains parent_id field information, you need to add the following two column fields to your blueprint file:
$table->unsignedinteger (' _lft '); $table->unsignedinteger (' _rgt ');
After setting up your model you just need to fix your tree to fill _lft and _rgt field:
Mymodel::fixtree ();
Relationship
Node has the following features, which are fully functional and preloaded:
Suppose we have a category model; The variable $node is an instance of the model that we operate on node. It can be a newly created node or a node that is removed from the database.
Inserting nodes (node)
Each time a node is inserted or moved to perform several database operations, it is strongly recommended to use transaction.
Watch out! the v4.2.0 version is not automatically turned on transaction, and node's structured operation requires manual save on the model, but some methods implicitly execute save and return the result of the Boolean type after the operation.
Creating nodes (node)
When you simply create a node, it is added to the end of the tree.
Category::create ($attributes); Automatic save is a root node (root)
Or
$node = new Category ($attributes); $node->save (); Save as a root node (root)
In this case, node is set to root, which means that it has no parent node
Set a node that already exists as root
#1 recessive save$node->saveasroot ();//#2 dominant Save$node->makeroot ()->save ();
Add a child node to the end or front end of a specified parent node
If you want to add a child node, you can add it as the parent node's first child node or the last child node.
* In the following example, $parent for a node that already exists
Methods to add to the end of the parent node include:
#1 use delay to insert $node->appendtonode ($parent)->save ();//#2 Use parent node $parent->appendnode ($node);//#3 With the parent node's children relationship $parent->children ()->create ($attributes);//#5 Parent relationship with child nodes $node->parent () Associate ($parent)->save ()//#6 with parent node Property $node->parent_id = $parent->id; $node->save ();//#7 Use static method Category::create ($attributes, $parent);
Methods to add to the front end of the parent node
#1 $node->prependtonode ($parent)->save ();//#2 $parent->prependnode ($node);
Insert a node before or after a specified node
You can use the following method to $node add an adjacent node as a specified node $neighbor
$neighbormust exist, either $node for the newly created node, or for the existing node, if $node it is already present, it will move to the new location $neighbor adjacent to it, and its parent will change if necessary.
# dominant Save$node->afternode ($neighbor)->save (), $node->beforenode ($neighbor)->save (); # hidden save$node-> Insertafternode ($neighbor); $node->insertbeforenode ($neighbor);
To build an array as a tree
However create , when you use a static method, it checks whether the array contains children keys and, if so, creates more nodes recursively.
$node = Category::create ([ ' name ' = = ' Foo ', ' children ' = ' = ' [ ' name ' = ' ' Bar ', ' Children ' + [ [' name ' = ' Baz '],], [],] ,] );
Now $node->children contains a set of nodes that have been created.
Rebuilding an array to a tree
You can easily recreate a tree, which is useful for saving a large number of modified tree structures.
Category::rebuildTree($data, $delete);
$dataAs an array representing the nodes
$data = [' id ' = = 1, ' name ' = ' foo ', ' children ' = [...]], [' name ' = ' = ' bar '],];
There is a name node for the above, foo it has the specified, which means that the existing id node will be populated, if the node does not exist, it is good to throw one ModelNotFoundException , in addition, the node has children an array, the array will be added to the node in the same way foo .
barThe node does not have a primary key, or it does not exist, and it will be created.
$deleteRepresents whether to delete data that already exists in the database but $data does not exist, by default it is not deleted.
Rebuilding subtrees
You can rebuild the subtree after the 4.3.8 version
Category::rebuildSubtree($root, $data);
This will restrict rebuilding only the $root subtree
Retrieving nodes
In some cases we need to use the variable $id to represent the primary key ID of the target node
Ancestors and descendants
Ancestors creates a parent chain of a node, which is helpful for showing the current kind of breadcrumbs.
Descendants is all child nodes of a parent node.
Both ancestors and descendants can be preloaded.
accessing ancestors$node->ancestors;//accessing descendants$node->descendants;
Load ancestors and descendants by customizing the query:
$result = Category::ancestorsof ($id); $result = Category::ancestorsandself ($id); $result = Category::d escendantsof ($id ); $result = Category::d escendantsandself ($id);
In most cases, you need to sort by hierarchy:
$result = Category::defaultOrder()->ancestorsOf($id);
Ancestor collections can be preloaded:
$categories = Category::with (' ancestors ')->paginate (30);//breadcrumbs In the View Template: @foreach ($categories as $i = $category) <small> $category->ancestors->count () implode (' > ', $category->ancestors->pluck (' name ') ->toarray ()): ' Top level ' </small><br> $category->name@endforeach
The entire ancestor is name removed and converted to an array, with > stitching as the string output.
Brother Node
Nodes that have the same parent node are called sibling nodes by each other
$result = $node->getsiblings (), $result = $node->siblings ()->get ();
Gets the neighboring sibling nodes:
Gets the next sibling node adjacent to $result = $node->getnextsibling ();//Gets all the sibling nodes behind $result = $node->getnextsiblings ();// Use the query to get all sibling nodes $result = $node->nextsiblings ()->get ();
Gets the neighboring front sibling nodes:
Gets the adjacent previous sibling node $result = $node->getprevsibling ();//Gets all the previous sibling nodes $result = $node->getprevsiblings ();// Use the query to get all sibling nodes $result = $node->prevsiblings ()->get ();
Get the relevant model of the table
Assuming each category has many goods, and hasmany relationship has been established, how to simply get $category and all of its descendants under all goods?
get descendants of id$categories = $category->descendants ()->pluck (' id '),//id$categories[with category itself] = $category GetKey ();//Get Goods$goods = Goods::wherein (' category_id ', $categories)->get ();
Contains node depth (depth)
If you need to know the level of node access:
$result = Category::withdepth ()->find ($id); $depth = $result->depth;
The root node (root) is the No. 0 layer (level 0), the child node of root is the first layer (level 1), and so on
You can use having constraints to get a specific level of nodes
$result = Category::withDepth()->having('depth', '=', 1)->get();
Note This is not valid in database strict mode
Default sort
All nodes are tightly organized internally, with no order by default, so nodes are randomly displayed, and this effect shows that you can sort the nodes alphabetically and in other order.
But in some cases it is necessary to show hierarchically, which is useful for getting ancestors and for menu order.
To use Deaultorder to sort the tree:
$result = Category::defaultOrder()->get();
You can also use reverse order:
$result = Category::reversed()->get();
Let the node move up and down within the parent to change the default ordering:
$bool = $node->down (); $bool = $node->up ();//Move Down 3 sibling nodes $bool = $node->down (3);
The operation returns a Boolean value that changes depending on the position of the node of the operation
Constraints
Many constraints can be used on these query constructors:
Whereisroot () gets only the root node;
Whereisafter ($id) gets all the nodes behind the node for a specific ID (not just the sibling node).
Whereisbefore ($id) gets all nodes in front of the node with a specific ID (not just the sibling node).
Ancestor constraints
$result = Category::whereancestorof ($node)->get (), $result = Category::whereancestororself ($id)->get ();
$nodeCan be a primary key or model instance of a model
descendant constraints
$result = Category::wheredescendantof ($node)->get (); $result = Category::wherenotdescendantof ($node)->get (); $ result = Category::orwheredescendantof ($node)->get (), $result = Category::orwherenotdescendantof ($node)->get ( ); $result = Category::wheredescendantandself ($id)->get ();//The result set contains the target node itself $result = Category:: Wheredescendantorself ($node)->get ();
Build tree
Once we get the result set of node, we can convert it to a tree, for example:
$tree = Category::get()->toTree();
This will add the parent and children relationships on each node, and you can use the recursive algorithm to render the tree:
$nodes = Category::get ()->totree () $traverse = function ($categories, $prefix = '-') use (& $traverse) { FOREAC H ($categories as $category) { echo php_eol. $prefix. ' '. $category->name; $traverse ($category->children, $prefix. '-'); }}; $traverse ($nodes);
This will resemble the following output:
-root--Child 1---Sub child 2-another Root
Build a flat tree
You can also build a flat tree: Place the child nodes directly behind the parent node. Useful when you get a custom sort of node and do not want to use recursion to loop your nodes.
$nodes = Category::get()->toFlatTree();
The previous example will output the following:
Rootchild 1Sub child 1Child 2Another Root
Building a subtree
Sometimes you don't need to load an entire tree, but you need only a few specific subtrees:
$root = Category::descendantsAndSelf($rootId)->toTree()->first();
With a simple query we can get the root node of the subtree and use the children relationship to get all of its descendants
If you don't need the $root node itself, you can do this:
$tree = Category::descendantsOf($rootId)->toTree($rootId);
Delete a node
Remove a node:
$node->delete();
Watch out! all descendants of the node will be deleted
Watch out! the node needs to be removed as a model, and the node cannot be deleted using the following statement:
Category::where('id', '=', $id)->delete();
This will destroy the tree structure
Support SoftDeletes for trait, and at the model level
Helper methods
Check if the node is a child of another node
$bool = $node->isDescendantOf($parent);
Check if it is a root node
$bool = $node->isRoot();
The other checks
$node->ischildof ($other);
$node->isancestorof ($other);
$node->issiblingof ($other);
$node->isleaf ()
Check consistency
You can check if the tree is broken.
$bool = Category::isBroken();
Get error Statistics:
$data = Category::countErrors();
It will return an array containing the keys
Oddness--Number of nodes with incorrect LFT and RGT values
Duplicates--The number of nodes that LFT or RGT value repeats
Wrong_parent--The number of nodes that cause invalid parent_id for left and RGT values that do not correspond to parent_id
Missing_parent--The number of nodes that have parent_id corresponding parent node not present
Repair Tree
Support the repair tree from v3.1, and set the appropriate LFT and RGT values for each node through the inheritance information of the parent_id field
Node::fixTree();
Scope (SCOPE)
Suppose you have a memu model and a MenuItems. They are one-to-many relations. MenuItems has menu_id properties and implements nested sets model. Obviously you want to handle each tree separately based on the menu_id attribute, in order to implement such a function, we need to specify this menu_id property as the scope property.
protected function Getscopeattributes () { return [' menu_id '];}
Now, in order to implement a custom query, we need to provide properties that need to restrict the scope.
menuitem::scoped ([' menu_id ' = 5])->withdepth ()->get (); Okmenuitem::d escendantsof ($id)->get (); Wrong:returns nodes from the other scopemenuitem::scoped ([' menu_id ' = 5])->fixtree ();
However, using the Model instance query Node,scope automatically deletes node based on the set restriction scope property. For example:
$node = Menuitem::findorfail ($id), $node->siblings ()->withdepth ()->get (); Ok
Use the instance to get the deleted query:
$node->newScopedQuery();
Note that you do not need to use scope when obtaining a model from a primary key
$node = Menuitem::findorfail ($id);//Ok$node = menuitem::scoped ([' menu_id ' = > 5])->findorfail (); OK, but extra