Giter Club home page Giter Club logo

baum's People

Contributors

beingtomgreen avatar bmitch avatar ceejayoz avatar daxborges avatar dirkpostma avatar dzcpy avatar etrepat avatar gerp avatar grahamcampbell avatar ignaciogc avatar james2037 avatar mpociot avatar robmeijer avatar superbuba avatar surt avatar ziadoz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

baum's Issues

Restoring a deleted model does not restore hierachical structure

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

Question about efficiency

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?

Sorting Nodes?

Is there a way to change the default sort so nodes are listed alphabetically under their respective parent nodes?

::roots() returns empty collection when scoped

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.

Use traits instead.

It might be nicer to use this feature if people didn't have to extend your particular model class to make use of it.

Support for PHP 5.3

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.

missing tablename prefix in column

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.

Getting an exception with the example from the site

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.

Accessing the ancestry/descendancy chain problem

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!

How to Get whole Tree Hierarchy ??

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 ??

Event for updating children while parent moved.

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.

How do Traverse Hierarchy?

Once you have a tree hierarchy using the ->toHiearchy() method how do you traverse it to output a

    list or options for a drop down list?

Can't use method return value in write context

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!

Scoping

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.

toHierarchy Method and unexpected behaviour

toHierarchy() method does not work as expected always
I have following category table
categories

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.

Is there a way to just dump the entire hierarchy?

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() ?

forceDelete() Fix

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());

Order by on Immediate Descendants (tested case)

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?

How to use with multilingual ?

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.

Nested with items

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 ?

Thing::roots()->orderBy('label') not working

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.

exception

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('&nbsp;', $this->lvl * 4) . $this->title;
    return $s;
}    

}

Laravel 4.1

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.

Moving root nodes

Can't move root nodes.
I have two root nodes $rootNodeOne and $rootNodeTwo

$rootNodeTwo->moveToLeftOf($rootNodeOne);

Got SQL error.

Inserting Model with scope

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?

makeRoot() fails on already existing items

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?

Upgrade to ~4

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.

Latest dev-develop commit throws error.

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}}

Call to a member function getConnection() on a non-object

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.

Add trunks() to complement leaves() methods

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);
  }

How to use with Pivot Tables?

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!

Eager loading children

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.

[Proposal] Nested tree Flat to hierarchical array

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;
        }

Testing a baum model and boot function

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() {

    }
}
?>

[ERROR] Using $this when not in object context

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;
    }

MakeRoot when already Root

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?

bug doesnt set nodes as root

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.

Moving nodes between scopes

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?

Beginner questions

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!

version 1.0.10

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

Exception when running Node::rebuild()

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()

[Proposal] Add getAncestorsNoRoot() and getAncestorsAndSelfNoRoot()

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().

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.