Love Fuel?    Donate

FuelPHP Forums

Ask your question about FuelPHP in the appropriate forum, or help others by answering their questions.
How to add new child for Nested Set Trees
  • Hi,

    I try to build a tree with the Nested Sets Package.

    Creating some root tree nodes is not the problem now. But when I would like to add my first Child, the left_id and right_id values don't to the expected changes.

    Here is my code:
    http://bin.fuelphp.com/snippet/view/ar

    Here is what happens in the database table:
    http://bin.fuelphp.com/snippet/view/as

    I don't know if this is correct, but when my rood nodes don't have the 1 as left_id nothing is working here anymore, as my root nodes are "gone".

    Does someknow what I am making wrong?

    Thanks
    Kay


  • You have to understand that every node in the try is (must be) a different object. If you do

    $tree->tree_new_first_child_of($tree);

    then you're trying to make the root a child of itself. Mess is guaranteed. ;-)

    So you need two objects for operations like this, the $parent, that must already exist in the tree, and the $child, which must be a new tree model object, and then you can do something like:

    $parent = Model_Tree::forge()->tree_get_root(); // $parent will now contain the root of the tree
    $child = Model_Tree::forge(); // create a new child object
    $child->tree_new_first_child_of($parent; // make $child a child of $parent



  • Hi Harro,

    as always: thanks for clarifying that to me.

    I work with multiple trees within one model so I changed it a little bit and first look for the correct tree:
    http://bin.fuelphp.com/snippet/view/at
    Is that code okay?

    It's very hard to find the right way of coding as I only have the CI DataMapper examples and you see that the way in Fuel is very different. :-( So sorry for asking so many stupid questions about that stuff.

    Is there any complete ready code example or even a side with an user interface I could have a look on?
    I still have some difficulties as I don't understand the whole concept of trees correctly I'm afraid. If there is any complete example in Fuel this would help me understanding what is how possible and how I have to setup my user interface for that. Actually I have many questionmarks in my mind if I am doing it in the right way.

    Thanks
    Kay
  • I don't think there are any examples out there. I converted it from DM to Fuel almost two years ago because someone asked for it, and haven't really looked at it since. I've got it on my todo list to rework it, and add it to the ORM package.

    For a bit of background on Nested Sets, see http://www.evanpetersen.com/item/nested-sets.html

    If I look at your code, I see

    $parent = \MetadataModel_Tree::find_by_tree_id(\Session::get('tree_id'))->tree_select();                              
    $child = \Metadata\Model_Tree::forge();
    $child->tree_id = \Session::get('tree_id');                                    
    $child->name = \Input::post('name');
    $child->tree_new_first_child_of($parent);

    I'm a bit confused by this code. You select a parent based on "tree_id". But "tree_id" identifies the entire tree, which can have lots of nodes. You need to select the parent on PK so you get the correct one.

    The tree_select() is not needed, it is used to store the id of the tree you're working on when you;re navigating the tree. It needs a tree id as a parameter (which you don't give), but since you're only creating a new node, you don't need it at all.

    Once you have the correct parent, this is indeed the way to add a new child (the first in the chain to be exact).
  • Hi Harro,

    the thing with tree_id was would like to use multiple trees within this model.
    So my idea was to give the current tree_id to the child. If I do that with the PK then this will not work if the ID and tree_id have not the same value (like when I add a new tree later).

    Is there a way to ask for this internal tree_id or should that be an other model?

    Sorry, but I am totally lost with that stuff.

    Regards Kay
  • You need the specific model object that will be the parent. The only way to get that object (this is unrelated to nested sets) is to do a find() on the PK. If you don't get a specific parent node first, how would it know where to insert the child in the tree?

    Once you have that parent you can forge() a new child object, do $child->tree_id = $parent->tree_id to make sure the child will be in the same tree as the parent.
  • Thanks, I got it now :-)

    I think I have now understood much more from the way Nested Set is working.
    Is it correct that bevore saving a new node, I always have to make some checkups?
    e.g.:
    1) If a Tree is empty, I have to add the first node as tree_new_first_child_of
    2) If I don't select any existing node, I have to add the node as tree_new_next_sibling_of
    3) If I want to add a new node between some existing node, I have to add the node as tree_new_previous_sibling_of

    Or should I make some Checkboxes or DropDown to let the User decide as what he will insert new nodes?

    One more question: if I would like to use tree_dump_as_array, what exactly do I have to add into that function as array()?

    Thanks, Kay
    1. If the tree is empty (i.e. no records with a specific "tree_id" exists, you first need to call tree_new_root(), creating the tree root:

      $root = Model_Tree::forge(array('name' => 'Root'))->tree_new_root();
       
    2. You always have to start with an existing node, either the tree root, or another node. Adding or deleteing nodes is always an operation relative to another node. Note that you can not add siblings to a tree root.

    3. You can add a node as a child (which means a level "lower" in the tree) or as a sibling (at the same level in the tree). Whether you use "previous" or "next" depends on which node you have selected as node to operate on.

    So if you look at the image in the readme of the repo:

    • "Customer Services" is a sibling of "Development Manager"
    • "Assistent 1" is a child of "Customer Services"
    • "Managing director" is parent of both "Customer Services" and  "Development Manager"

    So if you have the object $custserv (which contains the node "Customer Services"), then

    $custserv->tree_get_parent() will return the object for "Managing director"
    $custserv->tree_get_first_child() will return the object for "Assistent 1"
    $newnode->tree_new_first_child_of($custserv) will insert $newnode before "Assistent 1"
    $newmode->tree_new_next_sybling_of($assistent1) will insert $newnode between "Assistent 1" and "Assistent 2"


  • As for

    tree_dump_as_array(Array $attributes = array(), $skip_root = true, $hierarchical = false)

    you don't need to pass anything. The array allows you to select a subset of the properties of a node (for example only the 'id' and the 'name'). tree_dump_as_dropdown() uses this to create key/value pairs.

    $skip_root determines of the root node has to be part of the result (by default it is not), and $hierarchical determines of you get a flat array back as a result, or a multi-dimensional array (reflecting the tree structure).
  • Harro, so here is what I made so far:

    http://bin.fuelphp.com/snippet/view/ax

    Do you think it's a good start? Or any hints?

    Just solved only Childs and no Siblings. I am thinking of how I will do that right now. Any idea?

    Cheers, Kay
  • You can't use save() on a new tree object.

    If you do, left- and right pointers will not be added, so the node will not be part of the tree. Instead, use one of the tree_new... methods to save the new node to a particular location in the tree.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

In this Discussion