0

I have a task where I must to get hierarchy tree from given array. An arrays inside array looks:

$commentsArray = [
    [1, 1, 'Comment 1'],
    [2, 1, 'Comment 2'],
    [3, 2, 'Comment 3'],
    [4, 1, 'Comment 4'],
    [5, 2, 'Comment 5'],
    [6, 3, 'Comment 6'],
    [7, 7, 'Comment 7'],
];

now I need to get output into html like:

Comment 1
-- Comment 2
----Comment 3 
------Comment 6
----Comment 5
--Comment 4
Comment 7  

My code doesn't work:

<?php

$commentsArray = array(
    array(
        'id' => 1,
        'parent_id' => 1,
        'content' => 'Comment 1'
    ),
    array(
        'id' => 2,
        'parent_id' => 1,
        'content' => 'Comment 2'
    ),
    array(
        'id' => 3,
        'parent_id' => 2,
        'content' => 'Comment 3'
    ),
   ...
);

$new = array();

foreach ($commentsArray as $comment){
    $new[$comment['parent_id']][] = $comment;
}

$tree = createTree($new, array($commentsArray[0]));

echo '<pre>';
print_r($tree);
echo '</pre>';

function createTree(&$list, $parent){
    
    $tree = array();
    
    foreach ($parent as $k=>$l){
        
        if(isset($list[$l['id']])){
            $l['children'] = createTree($list, $list[$l['id']]);
        }
        
        $tree[] = $l;
    } 
    
    return $tree;
}

I tried to run script without first element of $commentsArray and it works but I need the first element

niceddev
  • 1
  • 2
  • Related content: [Recursive Multidimensional Array to HTML nested code](https://stackoverflow.com/q/42743019/2943403) , [create a unlimited multilevel nested list from a recursive array](https://stackoverflow.com/q/19283770/2943403) , [Build recursive nested menu from array](https://stackoverflow.com/q/23916237/2943403) , [How can I build a nested HTML list with an infinite depth from a flat array?](https://stackoverflow.com/q/9224229/2943403) , [How to obtain a nested HTML list from object's array recordset?](https://stackoverflow.com/q/8020947/2943403) – mickmackusa Feb 23 '23 at 22:36

3 Answers3

0
<?php

$comments = [
    [1, 1, 'Comment 1'],
    [2, 1, 'Comment 2'],
    [3, 2, 'Comment 3'],
    [4, 1, 'Comment 4'],
    [5, 2, 'Comment 5'],
    [6, 3, 'Comment 6'],
    [7, 7, 'Comment 7'],
];

$map = [];

foreach($comments as $c) {
    $id = $c[0] === $c[1] ? 0 : $c[1];
    $map[$id][] = $c;
}

function print_comments($arr, $depth) {
    global $map;
    foreach($arr as $c) {
        echo str_repeat("--", $depth) . "{$c[2]}\n";
        print_comments($map[$c[0]] ?? [], $depth+1);
    }
}

print_comments($map[0], 0);
  • 1
    Produces the output OP is looking for (https://3v4l.org/CAApZ). Your answer would be more valuable if you explained how the solution works. – Markus AO Feb 23 '23 at 17:38
0

I did it myself. But Thanks anyway!

<?php

class CommentService
{
/**
 * @param array $commentsArray
 *
 * @return string
 */
public function getHierarchyTreeDOM(array $commentsArray): string
{
    $processedIds = [];

    $htmlDOM = '<ul>';

    foreach ($commentsArray as $comment) {

        if ($comment[0] === $comment[1]) {
            $htmlDOM .= '<li>' . $comment[2];
            $htmlDOM .= $this->buildHierarchyRecursively($commentsArray, $comment[0], $processedIds);
            $htmlDOM .= '</li>';
        }

    }

    return $htmlDOM . '</ul>';
}

/**
 * @param array $commentsArray
 * @param int $parentId
 * @param array $processedIds
 *
 * @return string
 */
private function buildHierarchyRecursively(array $commentsArray, int $parentId = 1, array &$processedIds = []): string
{
    $htmlDOM = '<ul>';

    foreach ($commentsArray as $item) {

        if ($item[0] !== $parentId && $item[1] === $parentId && !in_array($item[0], $processedIds)) {
            $processedIds[] = $item[0];

            $htmlDOM .= '<li>' . $item[2];
            $htmlDOM .= $this->buildHierarchyRecursively($commentsArray, $item[0], $processedIds);
            $htmlDOM .= '</li>';
        }

    }

    return $htmlDOM . '</ul>';
}

}

Then in html page:

<?php

require_once('CommentService.php');

$commentService = new CommentService();

$commentsArray = [
    [1, 1, 'Comment 1'],
    [2, 1, 'Comment 2'],
    [3, 2, 'Comment 3'],
    [4, 1, 'Comment 4'],
    [5, 2, 'Comment 5'],
    [6, 3, 'Comment 6'],
    [7, 7, 'Comment 7'],
];

?>
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
      content="width=device-width, user-scalable=no, initial-scale=1.0, 
maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Comments</title>
</head>
<body>
    <h2>Comments:</h2>
    <?php

        echo $commentService->getHierarchyTreeDOM($commentsArray);

    ?>
</body>
</html>
niceddev
  • 1
  • 2
0

You could use two functions:

  • One to iteratively create the hierarchy structure.
  • One to recursively create HTML for that hierarchy.
function createForest(&$list) {
    $bykey = [0 => ["children" => []]];
    foreach ($list as [$id, $parentid, $comment]) {
        $bykey[$id] = ["comment" => $comment, "children" => []];
        $bykey[$parentid == $id ? 0 : $parentid]["children"][] = &$bykey[$id];
    }
    return $bykey[0]["children"];
}

function createHtml(&$forest) {
    $html = "";
    foreach ($forest as ["comment" => $comment, "children" => $children]) {
        $html .= "<li>$comment" . createHtml($children) . "</li>";
    }
    return $html ? "<ul>$html</ul>" : "";
}

$commentsArray = [
    [1, 1, 'Comment 1'],
    [2, 1, 'Comment 2'],
    [3, 2, 'Comment 3'],
    [4, 1, 'Comment 4'],
    [5, 2, 'Comment 5'],
    [6, 3, 'Comment 6'],
    [7, 7, 'Comment 7'],
];
$forest = createForest($commentsArray);
$html = createHtml($forest);
echo $html;

Output:

enter image description here

trincot
  • 317,000
  • 35
  • 244
  • 286