1

After collecting all qualifying rows from my database, I'm trying to extend the buildTree() function from this answer to also calculate the depth and running total in the hierarchial output.

My code manages to nest and calculate all elements correctly except the first level.

My db result array looks like this:

$array = [
    [
        'id'     => 196, 
        'name'   => 'Abilități spirituale', 
        'parent' => 0,
        'depth'  => 0,
        'score'  => 0,
        'sort'   => null,
    ],
    [
        'id'     => 395,
        'name'   => 'Date generale', 
        'parent' => 196,
        'depth'  => 0,
        'score'  => 0,
        'sort'   => 1,
    ],
    [
        'id'     => 201, 
        'name'   => 'Gândirea pozitivă', 
        'parent' => 197,
        'depth'  => 0,
        'score'  => 0,
        'sort'   => 1,
    ],
    [
        'id'     => 202, 
        'name'   => 'Satisfacția personală', 
        'parent' => 197,
        'depth'  => 0,
        'score'  => 0,
        'sort'   => 2,
    ],
    [
        'id'     => 203, 
        'name'   => 'Concordanța cu sine', 
        'parent' => 197,
        'depth'  => 0,
        'score'  => 0,
        'sort'   => 3,
    ],
    [
        'id'     => 204, 
        'name'   => 'Managementul calitativ al timpului liber', 
        'parent' => 197,
        'depth'  => 0,
        'score'  => 0,
        'sort'   => 4,
    ],
    [
        'id'     => 198, 
        'name'   => 'Armonia cu ceilalți', 
        'parent' => 196,
        'depth'  => 0,
        'score'  => 0,
        'sort'   => 3,
    ],
    [
        'id'     => 199, 
        'name'   => 'Sensul vieții și misiunea personală', 
        'parent' => 196,
        'depth'  => 0,
        'score'  => 0,
        'sort'   => 4,
    ],
    [
        'id'     => 200, 
        'name'   => 'Perspectiva de ansamblu asupra realității', 
        'parent' => 196,
        'depth'  => 0,
        'score'  => 0,
        'sort'   => 5,
    ],
    [
        'id'     => 197, 
        'name'   => 'Armonia cu sine', 
        'parent' => 196,
        'depth'  => 0,
        'score'  => 0,
        'sort'   => 2,
    ],
];

My code:

function buildTree(array $elements, $parentId = 0,$depth = 1) {
    $branch = array();
    global $TotalGeneral;
    foreach ($elements as $element) {
        if ($element['parent'] == $parentId) {
            $children = buildTree($elements, $element['id'],$depth+1);
        
            if ($children) {
                $TotalGeneral = 0;
                usort($children, function($a, $b) {
                    return $a['sort'] - $b['sort'];
                });
            
                foreach ($children as $c => $v){
                    $Total = getScore($v['id']);
                    $TotalGeneral += $Total;
                    $children[$c]['depth'] = $depth+1;
                    $children[$c]['score'] += $Total;
                }
            
                $Total = getScore($element['id']);
                $TotalGeneral += $Total;
                $element['depth'] = $depth; 
                $element['score'] += $TotalGeneral; 
                $element['children'] = $children;
            }else{
                $Total = getScore($element['id']);
                $TotalGeneral += $Total;
                // $element['score'] += $Total; 
            }
            // $element['score'] = $TotalGeneral; 
            $branch[] = $element;
        }
    }
    return $branch;
}

on print_r I get:

Array
(
    [0] => Array
        (
            [id] => 196
            [name] => Abilități spirituale
            [parent] => 0
            [depth] => 1
            [score] => 152 = WRONG VALUE
            [sort] =>


        [children] => Array
            (
                [0] => Array
                    (
                        [id] => 395
                        [name] => Date generale
                        [parent] => 196
                        [depth] => 2
                        [score] => 0
                        [sort] => 1
                    )

                [1] => Array
                    (
                        [id] => 197
                        [name] => Armonia cu sine
                        [parent] => 196
                        [depth] => 2
                        [score] => 145
                        [sort] => 2
                        [children] => Array
                            (
                                [0] => Array
                                    (
                                        [id] => 201
                                        [name] => Gândirea pozitivă
                                        [parent] => 197
                                        [depth] => 3
                                        [score] => 57
                                        [sort] => 1
                                    )

                                [1] => Array
                                    (
                                        [id] => 202
                                        [name] => Satisfacția personală
                                        [parent] => 197
                                        [depth] => 3
                                        [score] => 38
                                        [sort] => 2
                                    )

                                [2] => Array
                                    (
                                        [id] => 203
                                        [name] => Concordanța cu sine
                                        [parent] => 197
                                        [depth] => 3
                                        [score] => 29
                                        [sort] => 3
                                    )

                                [3] => Array
                                    (
                                        [id] => 204
                                        [name] => Managementul calitativ al timpului liber
                                        [parent] => 197
                                        [depth] => 3
                                        [score] => 21
                                        [sort] => 4
                                    )

                            )

                    )

                [2] => Array
                    (
                        [id] => 198
                        [name] => Armonia cu ceilalți
                        [parent] => 196
                        [depth] => 2
                        [score] => 54
                        [sort] => 3
                    )

                [3] => Array
                    (
                        [id] => 199
                        [name] => Sensul vieții și misiunea personală
                        [parent] => 196
                        [depth] => 2
                        [score] => 49
                        [sort] => 4
                    )

                [4] => Array
                    (
                        [id] => 200
                        [name] => Perspectiva de ansamblu asupra realității
                        [parent] => 196
                        [depth] => 2
                        [score] => 49
                        [sort] => 5
                    )

            )

    )

)
mickmackusa
  • 43,625
  • 12
  • 83
  • 136
morowind
  • 302
  • 1
  • 9
  • 24
  • When the initial call to the function returns, `$TotalGeneral` will contain the top-level total. The caller should put that into the first level of the array. – Barmar Sep 28 '16 at 21:42

1 Answers1

0
  1. To ensure that data mutations are preserved between recursive processing, modify all arrays by reference.

  2. As you iterate children add the retrieved score to the child and its parent.

  3. After fully processing a parent, push it into the returned tree array.

Code: (Demo)

function buildTree(array &$rows, int $parentId = 0, int $depth = 0): array
{
    $tree = [];
    foreach ($rows as &$row) {
        if ($row['parent'] !== $parentId) {
            continue;
        }
        $row['depth'] = $depth;

        $row['children'] = buildTree($rows, $row['id'], $depth + 1);
        usort(
            $row['children'],
            fn($a, $b) => $a['sort'] <=> $b['sort']
        );

        foreach ($row['children'] as &$child) {
            $row['score'] += $child['score'] += getScore($child['id']);
            $child['depth'] = $depth + 1;
        }
        $tree[] = $row;
    }
    return $tree;
}
       
var_export(
    buildTree($array)
);
mickmackusa
  • 43,625
  • 12
  • 83
  • 136