IDontKnow
IDontKnow

Reputation: 355

How to build tree structure for comments?

I am fetching all of the comments for blog post, also I put them in tree structure by using references with function below:

public function getComments($articleID) {
    $sql = "SELECT * FROM comments WHERE articleid = $articleID";
    $database = DatabaseFactory::getFactory()->Connect();
    $stmt = $database->query($sql);  
    $res = $stmt->fetchAll(PDO::FETCH_ASSOC);
    if($res!=NULL)
    {
        $references = array();
        $tree = array();
        foreach ($res as $id=> &$node) {
            // Use id as key to make a references to the tree and initialize it with node reference.
            $references[$node['comment_id']] = &$node;

            // Add empty array to hold the children/subcategories
            $node['children'] = array();

            // Get your root node and add this directly to the tree
            if ($node['comment_respond_to']==0) {
                $tree[$node['comment_id']] = &$node;
            } else {
                // Add the non-root node to its parent's references
                $references[$node['comment_respond_to']]['children'][$node['comment_id']] = &$node;
            }
        }

        return $tree;

When I print_r($tree); this is the output;

Array
(
    [1] => Array
        (
            [comment_id] => 1
            [articleid] => 1
            [user_id] => 2
            [comment_comment] => First comment.
            [comment_date] => 2016-03-10 20:06:43
            [comment_respond_to] => 0
            [children] => Array
                (
                    [2] => Array
                        (
                            [comment_id] => 2
                            [articleid] => 1
                            [user_id] => 1
                            [comment_comment] => First comment, first child.
                            [comment_date] => 2016-03-10 20:06:43
                            [comment_respond_to] => 1
                            [children] => Array
                                (
                                )
                    )

                [4] => Array
                    (
                        [comment_id] => 4
                        [articleid] => 1
                        [user_id] => 1
                        [comment_comment] => First comment, second child.
                        [comment_date] => 2016-03-10 20:06:43
                        [comment_respond_to] => 1
                        [children] => Array
                            (
                            )

                    )

            )

    )

[3] => Array
    (
        [comment_id] => 3
        [articleid] => 1
        [user_id] => 2
        [comment_comment] => Second comment.
        [comment_date] => 2016-03-10 20:06:43
        [comment_respond_to] => 0
        [children] => Array
            (
                [6] => Array
                    (
                        [comment_id] => 6
                        [articleid] => 1
                        [user_id] => 1
                        [comment_comment] => Second comment, first child.
                        [comment_date] => 2016-03-10 20:06:43
                        [comment_respond_to] => 3
                        [children] => Array
                            (
                            )

                    )

            )

    )

)       

Everything goes perfect.

Time to echo out.

My desired output:

  1. First Comment
    1. First comment, first child.
    2. First comment, second child.
  2. Second Comment
    1. Second comment, first child.

So, I know my next step should be creating loop with foreach and get the comments.

I replace return $tree; with;

        foreach ($tree as $key) {
            echo '<li>'.$key["comment_comment"], '</li>';
        }

It outputs;

  1. First Comment
  2. Second Comment

Child comments are missing. I know my next step should be creating another foreach inside of current foreach to get the child comments but I don't know how to do it.

I appreciate any help.

Upvotes: 3

Views: 2305

Answers (2)

Simon Kraus
Simon Kraus

Reputation: 736

You should use the key => value syntax in foreach. Do it something like this way:

    foreach ($tree as $key) {
    echo '<li>'.$key["comment_comment"], '</li>';
    if($key['children'])  {
        echo '<ul>';
        foreach($key['children'] as $child) {
            echo '<li>'.$child["comment_comment"], '</li>';
        }
        echo '</ul>';
    }

}

//edit: And if there are more then 1 child levels you should use recursive loops.

Upvotes: 3

VolkerK
VolkerK

Reputation: 96159

A simple solution would be to use recursion, e.g.

<?php
$comments = data();
foo($comments);

function foo($arr, $level=0) {
    $prepend = str_repeat(' ', $level); // <- the $level thingy is not necessary; it's only in here to get a bit prettier output

    echo $prepend, '<ul>', PHP_EOL;
    foreach($arr as $comment) {
        echo $prepend, '    <li>', $comment['comment_date'], ' ', htmlentities($comment['comment_comment']), PHP_EOL;
        if ( !empty($comment['children']) ) {
            foo($comment['children'], $level+1); // recurse into the next level
        }
        echo $prepend, '    </li>', PHP_EOL;
    }
    echo $prepend, '</ul>', PHP_EOL;
}


function data() {
    return array (
      1 => 
      array (
        'comment_id' => 1,
        'articleid' => 1,
        'user_id' => 2,
        'comment_comment' => 'First comment.',
        'comment_date' => '2016-03-10 20:06:43',
        'comment_respond_to' => 0,
        'children' => 
        array (
          2 => 
          array (
            'comment_id' => 2,
            'articleid' => 1,
            'user_id' => 1,
            'comment_comment' => 'First comment, first child.',
            'comment_date' => '2016-03-10 20:06:43',
            'comment_respond_to' => 1,
            'children' => 
            array (
            ),
          ),
          4 => 
          array (
            'comment_id' => 4,
            'articleid' => 1,
            'user_id' => 1,
            'comment_comment' => 'First comment, second child.',
            'comment_date' => '2016-03-10 20:06:43',
            'comment_respond_to' => 1,
            'children' => 
            array (
            14 => 
                  array (
                    'comment_id' => 14,
                    'articleid' => 1,
                    'user_id' => 99,
                    'comment_comment' => 'Comment to second child of First comment.',
                    'comment_date' => '2016-03-10 20:19:43',
                    'comment_respond_to' => 4,
                    'children' => 
                    array (
                    ),
                  ),
            ),
          ),
        ),
      ),
      3 => 
      array (
        'comment_id' => 3,
        'articleid' => 1,
        'user_id' => 2,
        'comment_comment' => 'Second comment.',
        'comment_date' => '2016-03-10 20:06:43',
        'comment_respond_to' => 0,
        'children' => 
        array (
          6 => 
          array (
            'comment_id' => 6,
            'articleid' => 1,
            'user_id' => 1,
            'comment_comment' => 'Second comment, first child.',
            'comment_date' => '2016-03-10 20:06:43',
            'comment_respond_to' => 3,
            'children' => 
            array (
            ),
          ),
        ),
      ),
    );
}

prints

<ul>
    <li>2016-03-10 20:06:43 First comment.
    <ul>
        <li>2016-03-10 20:06:43 First comment, first child.
        </li>
        <li>2016-03-10 20:06:43 First comment, second child.
        <ul>
            <li>2016-03-10 20:19:43 Comment to second child of First comment.
            </li>
        </ul>
        </li>
    </ul>
    </li>
    <li>2016-03-10 20:06:43 Second comment.
    <ul>
        <li>2016-03-10 20:06:43 Second comment, first child.
        </li>
    </ul>
    </li>
</ul>

Upvotes: 5

Related Questions