简体   繁体   中英

How to display comments in a nested way with parent ID

I have a table comments , thats look like this, added some mockup content as well:

+------------+---------+----------+-------------------+------------------------------------+---------------------------+
| comment_id | user_id | movie_id | comment_parent_id |          comment_content           | comment_creation_datetime |
+------------+---------+----------+-------------------+------------------------------------+---------------------------+
|         26 |       1 |    16329 |                 0 | Första                             | 2016-01-24 10:42:49       |
|         27 |       1 |    16329 |                26 | Svar till första                   | 2016-01-24 10:42:55       |
|         28 |       1 |    16329 |                26 | Andra svar till förta              | 2016-01-24 10:43:06       |
|         29 |       1 |    16329 |                28 | Svar till "andra svar till första" | 2016-01-24 10:43:23       |
+------------+---------+----------+-------------------+------------------------------------+---------------------------+

Im trying to display the comments Reddit style, like this image:

在此输入图像描述

Im trying to fetch all comments SELECT * FROM comments WHERE movie_id = :movie_id ORDER BY comment_creation_datetime DESC and then recursively echo them out.

I have tried a bunch of foreach loops, but none is working as expected

foreach($this->comments as $value){ ?>
    <div class="comment">
        Comment content <?php echo $value->comment_content; ?>
            <?php if($value->comment_parent_id > 0){
    foreach($value as $sub_comment){ ?>
                <div class="comment">
                    comment comment on comment: <?php echo $value->comment_content; ?>
                </div>
            <?php }} ?>
    </div>
<?php }

My question:

How do I echo out the comments in a nested Reddit style with foreach loop?

I would use some recursive function, you start with the ones with parent_id == 0 and recursively print all those who are their direct children.

This code is not tested, but you can get the idea:

function printComment($comment, $comments)
{
    foreach($comments as $c)
    {
        if($c->parent_id == $comment->comment_id)
        {
            $output .= "<li>".printCommment($c)."</li>";
        }
    }

    $output = "<ul>".$comment->comment_content."</ul>".$output;
    return $output;

}


foreach($this->comments as $comment)
{
    if($comment->parent_id == 0)
    {
        echo printComment($comment,$this->comments);
    }
}

Working with the adjacency list model can be more problematic with SQL. You need to retrieves all the rows with a single query and store a reference of any parent's child in a lookup table.

$sth = $pdo->prepare("SELECT * FROM comments WHERE movie_id = ? ORDER BY comment_creation_datetime DESC");
$sth->execute([$movie_id]);

$comments = $sth->fetchAll(PDO::FETCH_ASSOC);

$lookup_table = [];
foreach ($comments as $comment_key => $comment) {
    $lookup_table[$comment['comment_parent_id']][$comment_key] = $comment['comment_id'];
}

Now you can display them with

function recursive_child_display($comments, $lookup_table, $root = 0, $deep = 0)
{
    if (isset($lookup_table[$root])) {
        foreach ($lookup_table[$root] as $comment_key => $comment_id) {
            // You can use $deep to test if you're in a comment of a comment

            echo '<div class="comment">';
            echo 'Comment content ', $comments[$comment_key]['comment_content'];
            recursive_child_display($comments, $lookup_table, $comment_id, $deep+1);
            echo '</div>';
        }
    }
}

Example:

// display all the comments from the root
recursive_child_display($comments, $lookup_table, 0);

// display all comments that are parent of comment_id 26
recursive_child_display($comments, $lookup_table, 26);

You need to both make a list of root comments, and hierarchically organize all of them. You can do both in one go:

$roots = [];
$all = [];
foreach($comments as $comment)
{
  // Make sure all have a list of children
  $comment->comments = [];

  // Store all by ID in associative array
  $all[$comment->comment_id] = $comment;

  // Store the root comments in the roots array, and the others in their parent
  if(empty($comment->comment_parent_id))
    $roots[] = $comment;
  else
    $all[$comment->comment_parent_id]->comments[] = $comment;
}
// Check it's all done correctly!
print_r($roots);

You presorted the list by date, that's preserved in this approach. Also, as you only reorganized by reference this is lightning fast, and ready to be used in templating engines or anything - no need to print out inline like the other answers.

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