简体   繁体   中英

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 :

替代文字
(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)

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.

It is not possible to solve this problem without recursion. You need something like the following:

function tag_recursive($node, &$number) {
    $node->left = $number++;
    foreach ($node->children as &$child) {
        tag_recursive($child, $number);
    }
    $node->right = $number++;
}

function tag($node) {
    $number = 1;
    tag_recursive($node, $number);
    // $number is now highest id + 1
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM