Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP RecursiveIteratorIterator and nested sets

I have a set of objects in a hierachy. There's a top "root" node and that has child nodes, which in turn have child nodes etc. I'm trying to save this structure into a DB using the nested set model, where each "side" of each node is numbered to define the hierarchy, as in Managing Hierarchical Data in MySQL:

alt text
(source: mysql.com)

My problem is calculating the left and right values. I typically use RecursiveIteratorIterator to iterate over the hierarchy, but I cant work out how to calculate the numbers without resorting to a recursive function that parses an index variable by reference.

Any ideas?

It's probably of no use, but this is the (incorrect) code I currently have:

$iterator = new RecursiveIteratorIterator(
    new Node_List(array($root)),
    RecursiveIteratorIterator::SELF_FIRST);

$i = 0;     
foreach ($iterator as $node) {
    $node->left = ++$i;
    $node->right = ++$i;
}

As you can see, that would give something like this:

Node 
    Node 
    Node 

Left and right values of:

Node (1, 2)
    Node (3, 4)
    Node (5, 6)

When they should be:

Node (1, 6)
    Node (2, 3)
    Node (4, 5)
like image 834
Jack Sleight Avatar asked Oct 14 '22 17:10

Jack Sleight


1 Answers

I figured it out, here's the solution (simplifed):

$iterator = new RecursiveIteratorIterator(
    new Site_Node_List(array($root)),
    RecursiveIteratorIterator::SELF_FIRST);

$sides = array();
$s = 0;
$i = 0;
$parents = array();
foreach ($iterator as $item) {
    $js = array_splice($parents, $depth, count($parents), array($i));
    foreach (array_reverse($js) as $j) {
        $sides[$j]['right'] = ++$s;
    }
    $sides[$i]['left'] = ++$s;
    $i++;
}
foreach (array_reverse($parents) as $j) {
    $sides[$j]['right'] = ++$s;
}

This is am over simplified version of my actual code, as it just stores the "side" values in a separate array, but it demonstrates the principle.

The basic idea is that you store all the parent nodes (tracked by the depth value) in an array, and only write the "left" values in your loop. Then, when the depth decreases it means you've gone back up the hierarchy, so the parents array is spliced to remove the ones that are no longer relevant, and they are looped over (in reverse) setting the "right" values. Finally, you have to loop over the remaining parents at the end.

like image 140
Jack Sleight Avatar answered Oct 18 '22 12:10

Jack Sleight