etrepat / baum Goto Github PK
View Code? Open in Web Editor NEWBaum is an implementation of the Nested Set pattern for Laravel's Eloquent ORM.
Home Page: http://etrepat.com/baum
License: MIT License
Baum is an implementation of the Nested Set pattern for Laravel's Eloquent ORM.
Home Page: http://etrepat.com/baum
License: MIT License
I am able to delete a model with $model->delete();
and the lft
and rgt
variables of the parent model changes, but when you restore the model with $model->restore
, lft
and rgt
of the parent model stays the same. Is this intended or a bug?
Example:
before:
id | name | parent_id | lft | rgt | depth | delete_at
1 | root | null | 1 | 4 | 0 | null
2 | child | 1 | 2 | 3 | 1 | null
deleted:
id | name | parent_id | lft | rgt | depth | delete_at
1 | root | null | 1 | 2 | 0 | null
2 | child | 1 | 2 | 3 | 1 | (timestamp)
restored:
id | name | parent_id | lft | rgt | depth | delete_at
1 | root | null | 1 | 2 | 0 | null
2 | child | 1 | 2 | 3 | 1 | null
Hey,
First of all, great project, thanks for building it.
I was reading the theory behind nested sets which states
Nested sets are very slow for inserts because it requires updating left and right domain values for all records in the table after the insert. This can cause a lot of database thrash[citation needed] as many rows are rewritten and indexes rebuilt.
My use case is tags. Organisations have many tags, which they can use to tag other models that they own (e.g. assets). This seems similar to your categories example. However, unlike categories of which there may only be a small amount (say for a shop), there could be a lot of tags in that table. Everyone's tags from across the whole product, but they would only own / be able to access a subset of those. It would be possible that this table could get big, and I'm worried about the intensity of those rewrites that have to occur.
Any thoughts?
Thank you for implementing NestedSets for L4. How would you make multiple trees in one table?
Is there a way to change the default sort so nodes are listed alphabetically under their respective parent nodes?
I have $scoped
set to ['menu']
in my model, and I successfully built up some menus. The data looks fine in the database -- each of the four menus has a root node, and then some children, and each menu's root and children have the menu name in the menu
column.
But when I call MenuItem::roots()->get()
to get the four menus' root nodes I get an empty collection.
If at this point (with the data already in place) I comment out the lines from the model setting $scoped
and try again, I do get the four root nodes.
It seems something is wrong with the implementation of the roots
method -- perhaps it shouldn't be starting its query builder in the same way as other queries, because we don't actually want to constrain ourselves based on the scoped columns at this point.
It might be nicer to use this feature if people didn't have to extend your particular model class to make use of it.
It appears that this package was written with PHP 5.4 in mind, as it uses shorthand array syntax (i.e. ['foo', 'bar']). This feature was introduced in PHP 5.4, and subsequently causes parse errors in PHP 5.3.
It would be a good idea to use the traditional array definition syntax in order to make this package compatible with PHP >= 5.3.7, which is what Laravel 4 supports.
When I try to delete the a child node using
Foo::where(...)->delete()
the parent doesn't seem to update it's lft
and rgt
values.
when i write this code:
first(); ``` foreach($node->getLeaves() as $descendant) { echo "{$descendant->name}"; } ``` ?>I get this error:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'categoryLists.rgt' in 'where clause' (SQL: select * from cf_categoryLists
where lft
>= ? and lft
< ? and id
!= ? and categoryLists.rgt - categoryLists.lft = 1 order by lft
asc) (Bindings: array ( 0 => 1, 1 => 6, 2 => 3, ))
The error in the sql is that column names are not prefixed when they should be.
Now, I'm really not sure if it's just me being stupid or this is a real issue, but I've run into the problems (perhaps similar to the issue #17) while I was trying to run the example from your site:
$node = Category::where('name', '=', 'Books');
foreach($node->getDescendantsAndSelf() as $descendant) {
echo "{$descendant->name}";
}
When I run the above Laravel throws an exception:
Call to undefined method Baum\Extensions\Query\Builder::getDescendantsAndSelf()
Category is the model that was generated by artisan:
use Baum\Node;
class Category extends Node {
...
}
And as far as I can tell the bundle was properly installed, I followed the instructions closely.
If the above code is called like this:
$node = Category::where('name', '=', 'Books')->first();
foreach($node->getDescendantsAndSelf() as $descendant) {
echo "{$descendant->name}";
}
then it works fine because then the $node is a Category instance, but this way it runs 2 queries, instead of just one.
Hello!
In docs you wrote that i can dump a hierarchy tree in this way:
Category::where('name', '=', Books)->getDescendantsAndSelf()->toHierarchy();
Unfortunately it doesn't works.
The only way i could get the whole tree is this:
$category = Category::where('name', '=', Books)->first();
$category->getDescendantsAndSelf()->toHierarchy();
Is it my fault or it's a bug, or maybe it's a problem in the doc?
I'm using laravel 4.1 i dont't know if it's matter in this case.
Thanks!
I am using your package in my project . I want to know that how to get a tree hierarchy using your model ? ie in to a json tree or array tree ??
It would be useful to have an additional event handler for the case of updating children while it's parent has just moved. Currently, every descendant of moved node gets save()
'd here:
https://github.com/etrepat/baum/blob/master/src/Baum/Move.php#L120
However it's hard to distinguish if the saved
event of each descendant was fired due to parent's move within the tree. I think it would be useful for the descendant nodes to "know" that their parent has just moved, so they can be updated accordingly.
Once you have a tree hierarchy using the ->toHiearchy() method how do you traverse it to output a
Hey!
With PHP 5.4.9 and dev-develop branch of baum I get this error:
Can't use method return value in write context
open: vendor/baum/baum/src/Baum/Node.php
/**
* Returns wether this particular node instance is scoped by certain fields
* or not.
*
* @return boolean
*/
public function isScoped() {
return !empty($this->getScopedColumns());
}
Could you fix this for < PHP 5.5.x users, since returning empty with a function/method only works for 5.5.x.
Thanks!
Inspiration CakePHP Behaviors Tree
http://book.cakephp.org/2.0/en/core-libraries/behaviors/tree.html
regards
I tried the provided scoping example:
$root1 = Category::create(['name' => 'R1', 'company_id' => 1]);
$root2 = Category::create(['name' => 'R2', 'company_id' => 2]);
$child1 = Category::create(['name' => 'C1', 'company_id' => 1]);
$child2 = Category::create(['name' => 'C2', 'company_id' => 2]);
$child1->makeChildOf($root1);
$child2->makeChildOf($root2);
$root1->children()->get(); // <- returns $child1
$root2->children()->get(); // <- returns $child2
and got this in DB:
+----+------+-----------+------+------+-------+---------------------+---------------------+----------+
| id | name | parent_id | lft | rgt | depth | created_at | updated_at | ruler_id |
+----+------+-----------+------+------+-------+---------------------+---------------------+----------+
| 1 | R1 | NULL | 1 | 4 | 0 | 2013-07-31 14:06:49 | 2013-07-31 14:06:49 | 1 |
| 2 | R2 | NULL | 3 | 6 | 0 | 2013-07-31 14:06:49 | 2013-07-31 14:06:49 | 2 |
| 3 | C1 | 1 | 2 | 3 | 1 | 2013-07-31 14:06:49 | 2013-07-31 14:06:49 | 1 |
| 4 | C2 | 2 | 4 | 5 | 1 | 2013-07-31 14:06:49 | 2013-07-31 14:06:49 | 2 |
+----+------+-----------+------+------+-------+---------------------+---------------------+----------+
I'm not sure if this is expected. This is almost the same result as if
protected $scoped = array('ruler_id');
was not set at all.
I was expecting data structure such that if I delete from table where ruler_id 2 I'm left with a fully functional data set, but that's not the case.
Further more, I don't see a need for root nodes that would hold their forests. Use case example might be a Stores table as a parent of Categories table, where Categories table has a store_id as a scope. If I want to use scopes in this scenario I would have to first create a store node inside a Categories table where in fact I don't need it at all, and it pragmatically doesn't belong there.
I hope I explained the issue well enough.
I'm currently creating a project with laravel 4.1 and wanted to use Baum :-)
toHierarchy()
method does not work as expected always
I have following category table
When we use
case 1: Category::all()->toHierarchy()
it works fine
case 2:
Category::where('name','=','Child 1')->getDescendantsAndSelf(array('id','name'))->toHierarchy()
as given in the documentation it
gives error "Call to undefined method Baum\Extensions\Query\Builder::getDescendantsAndSelf()"
case 3: Category::where('name','=','Child 1')->first()->getDescendantsAndSelf(array('id','name'))->toHierarchy
gives wrong hierarchy tree as following
|-Child 1
| -- Child 1.1
| -- Child 1.2
Rather it should give
|-Child 1
| -- Child 1.1
| -- Child 1.2
What is getting wrong? Or I am not using it proper way? Thank you.
I noticed that toHierarchy()
can only be used on a single root node. Is there an easy way to just dump out the complete hierarchy of all roots for a given scope, their descendants, and put that all into a hierarchy?
Something like Menu::roots(scope_id)->toHierarchy()
?
I was getting the following error when I was trying to truly delete a soft deleted object:
Call to a member function getAttributes() on a non-object
I believe the following should fix the issue:
In:
src/Baum/Extensions/Eloquent/Model.php
Change Line 19 From:
$fresh = static::find($this->getKey());
To:
$fresh = static::withTrashed()->find($this->getKey());
This:
$immediateDescendants = static::where('parent_id', $root->id)->orderBy('order')->get();
And
$immediateDescendants = $root->immediateDescendants()->orderBy('order')->get();
Return the same results but the second case does not obey the 'order'. Is this the intended behaviour?
I need multilingual usage, categories names for each language are stored in another table with relationship on PK id.
How to do that ?
Thanks for help.
I understand this nested is for managing category but how do I attach item to it let's say my Item belongs to women and dress.
Do I create another table to say item belongs to index of women and dress ? or does this package has got some function to handle this ?
This is a fantastic thing you have done here, thank you.
I controllers I have been trying to order the roots using something like Thing::roots()->orderBy('label'). It's not working and i am not getting any errors. There are other ways i can do this, but I figured I would leave a note here in the off case that it should be working.
in my app, i have tree structures with unlimited hierarchy depth.
user wants to get a nodes descendants, but as it may by so big, i want to get limited descendancy level (e.g. 5 levels of children), and later, if user want's, load more descendants.
Hi.
When i'm trying to use your extension i've got next exception:
"Call to undefined method Baum\Extensions\Query\Builder::getResults()"
How can i fix it?
My model declaration:
class Page extends Baum\Node
{
protected $table='cnt_page';
// 'lft' column name
protected $leftColumn = 'lft';
// 'rgt' column name
protected $rightColumn = 'rgt';
// 'depth' column name
protected $depthColumn = 'lvl';
// guard attributes from mass-assignment
protected $guarded = array('id', 'parent_id', 'lft', 'rgt', 'lvl');
public function author()
{
return $this->belongsTo('User', 'author_id');
}
public function getIdentedTitleAttribute() {
$s = str_repeat(' ', $this->lvl * 4) . $this->title;
return $s;
}
}
Now that laravel 4.1 is out, can you please update the composer file, so it can be used here aswell? Right now it conflicts.
Please update to include 4.1 support.
Thanks!
Can't move root nodes.
I have two root nodes $rootNodeOne and $rootNodeTwo
$rootNodeTwo->moveToLeftOf($rootNodeOne);
Got SQL error.
It seems that model events are not fired in Baum\Node
subclasses. Baum\Node
's are fired but it does not continue to fire additional ones.
I need to investigate Model events further.
When inserting a new Model with a defined scope, the
setDefaultLeftAndRight
function doesn't take the scope into account.
I thought rewriting it to something like this would fix the problem, but then moving nodes between scopes makes problems and the testMoveNodeBetweenScopes
fails:
$withHighestRightQuery = $this->newQuery()->orderBy($this->getRightColumnName(), 'desc')->take(1);
if ( !empty($this->scoped) ) {
foreach($this->scoped as $scopeFld)
$withHighestRightQuery->where($scopeFld, '=', $this->$scopeFld);
}
$withHighestRight = $withHighestRightQuery->first();
$maxRgt = 0;
if ( !is_null($withHighestRight) ) $maxRgt = $withHighestRight->getRight();
$this->setAttribute($this->getLeftColumnName() , $maxRgt + 1);
$this->setAttribute($this->getRightColumnName() , $maxRgt + 2);
Do you have any idea how to solve this problem?
Hello,
I have a table and want to make it a nested set table. So I added the neccessary columns and adding new elements/items to that table works really well.
However, I have to convert the already existing items to root elements. I tried the following:
Category::find(2)->makeRoot();
However, I'm running into the following error then:
PHP Fatal error: Uncaught exception 'InvalidArgumentException' with message 'Value must be provided.' in /var/www/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php:350
Stack trace:
#0 [internal function]: Illuminate\Database\Query\Builder->where('lft', '<=', NULL)
#1 /var/www/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(606): call_user_func_array(Array, Array)
#2 /var/www/vendor/baum/baum/src/Baum/Node.php(405): Illuminate\Database\Eloquent\Builder->where('lft', '<=', NULL)
#3 /var/www/vendor/baum/baum/src/Baum/Node.php(385): Baum\Node->ancestorsAndSelf()
#4 /var/www/vendor/baum/baum/src/Baum/Node.php(756): Baum\Node->getRoot()
#5 /var/www/vendor/d11wtq/boris/lib/Boris/EvalWorker.php(133) : eval()'d code(1): Baum\Node->makeRoot()
#6 /var/www/vendor/d11wtq/boris/lib/Boris/EvalWorker.php(133): eval()
#7 /var/www/vendor/d11wtq/boris/lib/Boris/Boris.php(171): Boris\EvalWorker->start()
#8 /var/www/vendor/laravel/framework/src/Illuminate/Foundation/Console/TinkerCommand.php(49): Boris\Boris in /var/www/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php on line 350
The error is clear, but I don't know how to solve it? Am I doing sth wrong? Or is there any other solution to my problem?
Hi, this looks to be an excellent package, exactly what I was looking for.
Do you have a time scale for merging the develop branch into master to update the Laravel dependencies to ~4? I'm currently working with the develop branch and everything looks to be working correctly.
After installing latest dev-develop 4bddc73 commit now i have error in my js console.
{"error":{"type":"Symfony\Component\Debug\Exception\FatalErrorException","message":"Call to a member function getConnection() on a non-object","file":"C:\Htdocs\at.univemba.com\uv2\vendor\laravel\framework\src\Illuminate\Database\Capsule\Manager.php","line":84}}
When calling makeRoot() or makeChildOf() I get the following error:
Call to a member function getConnection() on a non-object
Error occurs in vendor/laravel/framework/src/Illuminate/Database/Capsule/Manager.php. When returning to an older version of Baum this doesn't happen.
Hi,
It'd be great if Node had a trunks() family of methods to retrieve all descendants which aren't leaves. Something like:
public function trunks() {
$grammar = $this->getConnection()->getQueryGrammar();
$rgtCol = $grammar->wrap($this->getQualifiedRightColumnName());
$lftCol = $grammar->wrap($this->getQualifiedLeftColumnName());
return $this->descendants()
->whereRaw($rgtCol . ' - ' . $lftCol . ' != 1');
}
public function getTrunks($columns = array('*')) {
return $this->trunks()->get($columns);
}
public static function allTrunks() {
$instance = new static;
$grammar = $instance->getConnection()->getQueryGrammar();
$rgtCol = $grammar->wrap($instance->getQualifiedRightColumnName());
$lftCol = $grammar->wrap($instance->getQualifiedLeftColumnName());
return $instance->newNestedSetQuery()
->whereRaw($rgtCol . ' - ' .$lftCol . ' != 1');
}
public function isTrunk() {
return $this->exists && ($this->getRight() - $this->getLeft() != 1);
}
Hello, can anyone help me find out, how to use baum with Pivot Tables?
I have created those tables:
Categories table:
categories
- id
- name
...
Articles table:
articles
- id
- title
...
Articles and categories table
article_category
- id
- category_id
- article_id
The categories tree looks like this:
News - ID - 1 (Root)
...
Sport - ID - 2 (Root)
- Soccer - ID ( 3 ) ( Parent - Sport )
- Basketball - ID ( 4 ) ( Parent - Sport )
...
in my Article model I have categories() method
public function categories() {
return $this->belongsToMany('Category');
}
So, what I need is here, to get all Articles from Sport's Category ( including Soccer and Basketball ).
Can anyone help me to write that 'query'?
Thanks!
Perhaps README should countain examples how queries with related models work?
How do I eager load all a model's descendants? I'm traversing the tree from a given node and every time I ask for a node's children it's sending out another database query. They're really adding up.
I'm using toHierarchy in a different area of my code which already seems very awkward since I have to get a single Node model, then call the method, and now I've got a collection I need to get the first element of again. I can live with that, though I'd prefer to just start with the Node and be able to grab children without a new query actually being made, having already preloaded all children. But anyway, when I traverse through the Collection toHierarchy gave me I still get new database queries getting fired off.
In that case I'm doing
$menus = [];
foreach (MenuItem::roots()->get() as $root) {
$menus[$root->menu] = $root->getDescendantsAndSelf()->toHierarchy();
}
The view has
@foreach ($menus as $menu => $hierarchy)
<?php $root = $hierarchy->first(); ?>
<div class="menu panel panel-primary" data-id="{{{ $root->getKey() }}}">
...
@include('admin.menu-items.children', ['model' => $root])
...
</div>
@endforeach
The children partial view has
<ol class="nested-sortable">
@foreach ($model->children as $node)
@include('admin.menu-items.item', ['model' => $node, 'parentId' => $model->getKey()])
@endforeach
</ol>
The item partial view prints an <li>
in which the children partial is called again recursively on $model. There are more and more queries being fired off.
Would be good to have this addition somewhere. Maybe in the collection returned? I didn't examine closely a way to override the Collection sets in Eloquent.
It takes a flat array with all the tree and converts it in a hierarchical array. I setted a path specifically for my models, it would be better having the option to specify a path settings or something.
I took it from: http://www.sitepoint.com/forums/showthread.php?143727-Converting-Nested-Set-Array-into-a-Nested-Array
function nestedArray(&$result, $right = 'rgh', $left = 'lft', $path = '', $level = -1) {
$new = array();
if(is_array($result)) {
while(list($n, $sub) = each($result)) {
$subId = $sub['id'];
$new[$subId] = $sub;
$alias = (isset($sub['data']))?$sub['data']['alias']:'';
$new[$subId]['_tree_path'] = $path.'/'.$alias;
$new[$subId]['_tree_level'] = $level + 1;
if($sub[$right] - $sub[$left] != 1) {
// recurse ($result is manipulated by reference!)
$new[$subId]['children'] = nestedArray($result, $right, $left, $new[$subId]['_tree_path'], $new[$subId]['_tree_level']);
}
$next_id = key($result);
if($next_id && $result[$next_id]['parent_id'] != $sub['parent_id']) {
return $new;
}
}
}
return $new;
}
Hey,
was just fighting with my very simple test function for my CategoryRepository (which extends my category node model) for two hours.
What I was trying to do:
Setup a simple category structure for testing within the setUp() test function. This works on the first test but if it comes to my second test the initialization of my test data it is not!
I found out it belongs to the way of binding the creating event within the boot function of Node.php .
Actually I have no idea if there is a better way for baum. I got it working for me by adding
CategoryRepository::boot();
within the setUp() of my CategoryRepositoryTest ...
This also belongs to this topic: laravel/framework#1181
<?php
use Zizaco\FactoryMuff\Facade\FactoryMuff;
class CategoryRepositoryTest extends TestCase
{
public function setUp()
{
parent::setUp();
$this->Repository = new CategoryRepository;
// This isfixing this problem https://github.com/laravel/framework/issues/1181
CategoryRepository::boot();
// Generate a category tree database
$this->root1 = FactoryMuff::create('CategoryRepository');
$this->root2 = FactoryMuff::create('CategoryRepository');
$this->cat1 = FactoryMuff::create('CategoryRepository');
$this->cat2 = FactoryMuff::create('CategoryRepository');
$this->cat3 = FactoryMuff::create('CategoryRepository');
// Build levels
$this->cat1->makeChildOf($this->root1);
$this->cat2->makeChildOf($this->root2);
$this->cat3->makeChildOf($this->cat1);
}
public function testSetup() {
$this->assertTrue( $this->root1->isRoot() ,'root1 is not a root cat');
$this->assertTrue( $this->root2->isRoot() ,'root2 is not a root cat');
$this->assertFalse( $this->cat1->isRoot() ,'cat1 is a root cat');
$this->assertFalse( $this->cat3->isRoot() ,'cat2 is a root cat');
$this->assertEquals( $this->cat1->parent_id, $this->cat1->parent()->first()->id ,'cat1 is not a child of root1');
$this->assertEquals( $this->cat3->parent_id, $this->cat1->id ,'cat3 is not a child of cat1');
}
public function testGetTree() {
}
public function testGetTree2() {
}
}
?>
I'm sorry if i implemented wrong but i cant get around this error. This error is thrown on /vendor/baum/baum/src/Baum/Node.php on line 697.
/**
Sets the depth attribute
*
@return \Baum\Node
*/
public function setDepth() {
$this->getConnection()->transaction(function() {
-----> $this->reload();
$level = $this->getLevel();
$this->newQuery()->where($this->getKeyName(), '=', $this->getKey())->update(array($this->getDepthColumnName() => $level));
$this->setAttribute($this->getDepthColumnName(), $level);
});
return $this;
}
When I'm trying to rebuild my whole tree structure, I get an error on my first root node when I call $node->makeRoot();
I'm looping through an array which contains all the new data.
new array:
[0] => array( id => 1, children => array( [0] => array( id => 3 ), [1] => array( id => 2 ), ), )
old array, id 2 and 3 switched
Code:
function changeTree(parentId, $children) { $parent = getNodeFromDB($parentId); foreach($children as $child) { $node = getNodeFromDB($child['id']); if(empty($parent)) { //IS ROOT $node->makeRoot(); } else { //IS CHILD OF $PARENT $node->makeChildOf($parent); } if(!empty($child['children'])) { $this->changeTree($parent->id, $child['children']); } } }
Error 'A node cannot be moved to itself.' is set at the first node which is a root node (parentId = 0)
How can I change this to rebuild my whole tree structure?
Hi there,
I just ran into this bug. When having a node with parent_id set, setting parent_id to null will not result in the node being made root. I figured the reason lies in the function Node.php/storeNewParent()
public function storeNewParent() {
$dirty = $this->getDirty();
if ( isset($dirty[$this->getParentColumnName()]) )
Instead it should be
public function storeNewParent() {
if ( $this->isDirty($this->getParentColumnName()) && !(!$this->exists && $this->isRoot()) ) {
As isset returns false when the value is null, the is_null in the following function moveToNewParent() can otherwise never be true.
Edit: Added check to avoid setting new root node as root again - this throws an error in makeRoot() otherwise.
I was having this issue on master, and have just upgraded to develop and have the same behaviour.
I have a drag-and-drop front end to a nested menu system, with multiple menus (scopes) visible on the same page. The user can drag menu items from one menu to another.
We've been seeing some issues with items suddenly disappearing after dragging from menu to menu, and a look at the database shows that the depth is being incremented for unknown reasons.
I tried some testing on my own environment and I noticed pretty early that certain values aren't being updated in one situation. That situation is as follows:
I start with my default menu hierarchy (fresh from db:seed, this is stock and the numbers all look right). Two of the menus roots are empty (footer_left and sub).
+-----+--------------+-----------+------+------+-------+----------------------+
| id | menu | parent_id | lft | rgt | depth | name |
+-----+--------------+-----------+------+------+-------+----------------------+
| 561 | footer_left | NULL | 1 | 2 | 0 | NULL |
| 562 | footer_right | NULL | 1 | 16 | 0 | NULL |
| 563 | footer_right | 562 | 2 | 3 | 1 | Food & Drink |
| 564 | footer_right | 562 | 4 | 5 | 1 | Accommodations |
| 565 | footer_right | 562 | 6 | 7 | 1 | Event Calendar |
| 566 | footer_right | 562 | 8 | 9 | 1 | Things to Do |
| 567 | footer_right | 562 | 10 | 11 | 1 | Travel Deals |
| 568 | footer_right | 562 | 12 | 13 | 1 | Itineraries |
| 569 | footer_right | 562 | 14 | 15 | 1 | Blog |
| 550 | main | NULL | 1 | 20 | 0 | NULL |
| 551 | main | 550 | 2 | 9 | 1 | Festivals and Events |
| 552 | main | 551 | 3 | 4 | 2 | Food & Drink |
| 553 | main | 551 | 5 | 6 | 2 | Accommodations |
| 554 | main | 551 | 7 | 8 | 2 | Event Calendar |
| 555 | main | 550 | 10 | 17 | 1 | Things to Do |
| 556 | main | 555 | 11 | 12 | 2 | Food & Drink |
| 557 | main | 555 | 13 | 14 | 2 | Accommodations |
| 558 | main | 555 | 15 | 16 | 2 | Event Calendar |
| 559 | main | 550 | 18 | 19 | 1 | Travel Deals |
| 560 | sub | NULL | 1 | 2 | 0 | NULL |
+-----+--------------+-----------+------+------+-------+----------------------+
I drag the "Food & Drink" item (523) from the footer_right menu to the footer_left menu. I verify that the input I am sending to my back end is right -- I'm sending menu, parent_id, lft, rgt, depth for each item ID.
My back end code loads all the MenuItem objects and orders them by menu and then lft. I loop through once and update the 'menu' property of each, in case any need to change scope. Then I loop through in that order again and for each one except root nodes (whether it's been edited or not -- detecting reorderings etc seems like a lot of work) I reload $node and $parentNode to ensure data is fresh and then run $node->makeChildOf($parentNode)
. This works just fine and reorders things as expected as long as I'm just reordering within a particular menu/scope, but in this example where I'm moving from one scope to another I get an unexpected result.
+-----+--------------+-----------+------+------+-------+----------------------+
| id | menu | parent_id | lft | rgt | depth | name |
+-----+--------------+-----------+------+------+-------+----------------------+
| 561 | footer_left | NULL | 1 | 2 | 0 | NULL |
| 563 | footer_left | 562 | 2 | 3 | 1 | Food & Drink |
| 562 | footer_right | NULL | 1 | 16 | 0 | NULL |
| 564 | footer_right | 562 | 4 | 5 | 1 | Accommodations |
| 565 | footer_right | 562 | 6 | 7 | 1 | Event Calendar |
| 566 | footer_right | 562 | 8 | 9 | 1 | Things to Do |
| 567 | footer_right | 562 | 10 | 11 | 1 | Travel Deals |
| 568 | footer_right | 562 | 12 | 13 | 1 | Itineraries |
| 569 | footer_right | 562 | 14 | 15 | 1 | Blog |
| 550 | main | NULL | 1 | 20 | 0 | NULL |
| 551 | main | 550 | 2 | 9 | 1 | Festivals and Events |
| 552 | main | 551 | 3 | 4 | 2 | Food & Drink |
| 553 | main | 551 | 5 | 6 | 2 | Accommodations |
| 554 | main | 551 | 7 | 8 | 2 | Event Calendar |
| 555 | main | 550 | 10 | 17 | 1 | Things to Do |
| 556 | main | 555 | 11 | 12 | 2 | Food & Drink |
| 557 | main | 555 | 13 | 14 | 2 | Accommodations |
| 558 | main | 555 | 15 | 16 | 2 | Event Calendar |
| 559 | main | 550 | 18 | 19 | 1 | Travel Deals |
| 560 | sub | NULL | 1 | 2 | 0 | NULL |
+-----+--------------+-----------+------+------+-------+----------------------+
So, id 563, the one I moved, has changed scope. But note that its parent_id has not changed. Its lft and rgt happen to be right, but they're the same as they were before (which was also right). The depth is right. But also note that the footer_left root's lft and rgt have not been updated -- in particular, the rgt should now be 4. footer_right's subtree hasn't updated its lft and rgt values either, but I'm not sure if that's an issue or not.
So something above is broken.
It gets interesting when I move a different menu item. Re-seeding the database I have this:
+-----+--------------+-----------+------+------+-------+----------------------+
| id | menu | parent_id | lft | rgt | depth | name |
+-----+--------------+-----------+------+------+-------+----------------------+
| 581 | footer_left | NULL | 1 | 2 | 0 | NULL |
| 582 | footer_right | NULL | 1 | 16 | 0 | NULL |
| 583 | footer_right | 582 | 2 | 3 | 1 | Food & Drink |
| 584 | footer_right | 582 | 4 | 5 | 1 | Accommodations |
| 585 | footer_right | 582 | 6 | 7 | 1 | Event Calendar |
| 586 | footer_right | 582 | 8 | 9 | 1 | Things to Do |
| 587 | footer_right | 582 | 10 | 11 | 1 | Travel Deals |
| 588 | footer_right | 582 | 12 | 13 | 1 | Itineraries |
| 589 | footer_right | 582 | 14 | 15 | 1 | Blog |
| 570 | main | NULL | 1 | 20 | 0 | NULL |
| 571 | main | 570 | 2 | 9 | 1 | Festivals and Events |
| 572 | main | 571 | 3 | 4 | 2 | Food & Drink |
| 573 | main | 571 | 5 | 6 | 2 | Accommodations |
| 574 | main | 571 | 7 | 8 | 2 | Event Calendar |
| 575 | main | 570 | 10 | 17 | 1 | Things to Do |
| 576 | main | 575 | 11 | 12 | 2 | Food & Drink |
| 577 | main | 575 | 13 | 14 | 2 | Accommodations |
| 578 | main | 575 | 15 | 16 | 2 | Event Calendar |
| 579 | main | 570 | 18 | 19 | 1 | Travel Deals |
| 580 | sub | NULL | 1 | 2 | 0 | NULL |
+-----+--------------+-----------+------+------+-------+----------------------+
If I now move 'Accommodations' (584) from footer_right to footer_left, I end up with this:
+-----+--------------+-----------+------+------+-------+----------------------+
| id | menu | parent_id | lft | rgt | depth | name |
+-----+--------------+-----------+------+------+-------+----------------------+
| 581 | footer_left | NULL | 1 | 4 | 0 | NULL |
| 584 | footer_left | 581 | 2 | 3 | 1 | Accommodations |
| 582 | footer_right | NULL | 1 | 16 | 0 | NULL |
| 583 | footer_right | 582 | 4 | 5 | 1 | Food & Drink |
| 585 | footer_right | 582 | 6 | 7 | 1 | Event Calendar |
| 586 | footer_right | 582 | 8 | 9 | 1 | Things to Do |
| 587 | footer_right | 582 | 10 | 11 | 1 | Travel Deals |
| 588 | footer_right | 582 | 12 | 13 | 1 | Itineraries |
| 589 | footer_right | 582 | 14 | 15 | 1 | Blog |
| 570 | main | NULL | 1 | 20 | 0 | NULL |
| 571 | main | 570 | 2 | 9 | 1 | Festivals and Events |
| 572 | main | 571 | 3 | 4 | 2 | Food & Drink |
| 573 | main | 571 | 5 | 6 | 2 | Accommodations |
| 574 | main | 571 | 7 | 8 | 2 | Event Calendar |
| 575 | main | 570 | 10 | 17 | 1 | Things to Do |
| 576 | main | 575 | 11 | 12 | 2 | Food & Drink |
| 577 | main | 575 | 13 | 14 | 2 | Accommodations |
| 578 | main | 575 | 15 | 16 | 2 | Event Calendar |
| 579 | main | 570 | 18 | 19 | 1 | Travel Deals |
| 580 | sub | NULL | 1 | 2 | 0 | NULL |
+-----+--------------+-----------+------+------+-------+----------------------+
Again, I'm not sure if it's an issue that footer_right root and children's lft and rgt values haven't changed, but this time the moved node 584 has the correct parent_id, lft and rgt, and the footer_left root 581 has the correct lft and rgt too.
The issue above occurs whether I run MenuItem::rebuild() after all this or not. I also tried running MenuItem::rebuild() between passes (after I change the scopes where necessary), and I have the same issue.
Is there something I'm doing wrong? Or is this a bug?
Hello there,
Sorry but i could answer my own questions by looking at the docs or the example. Firstly, when i copy paste syntax like this "$root = Category::create(['name' => 'Root category']);", then i get an error. (Laravel 4.1, PHP 5.3.10 on Ubuntu 12.04)
Is this because i should really pass an array as so: "$root = Category::create(array('name' => 'Root category'));" ? Because when i do that, a new Root category does get added into my categories table.
Then, imagine i added a bunch of Root categories. How do i loop over them? The below will not work.
$categories = Category::roots();
foreach($categories as $c){
print $c->name;
}
Thanks!
Hi I download the newest version
There is a run out of memory problem when I use the makeChildOf method.
I configure the php.ini file
Nothing change.
But when I use version 1.0.9, it works perfectly
I'm trying to use the develop branch. When I run the rebuild static method I get an exception:
Call to undefined method Baum\Extensions\Query\Builder::rebuild()
It would be convenient to have these self explanatory functions, e.g. to display a breadcumb path, but without the root.
Background: I like to have a one-tree table because that saves me from having to program HTTP request functions for addRoot(). With 1 tree, it's enough to have only addChild().
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.