如何使用父ID以嵌套方式显示注释

时间:2016-01-24 12:32:16

标签: php

我有一个表comments,看起来像这样,还添加了一些模型内容:

+------------+---------+----------+-------------------+------------------------------------+---------------------------+
| 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       |
+------------+---------+----------+-------------------+------------------------------------+---------------------------+

我试图显示评论Reddit样式,如下图所示:

enter image description here

我试图获取所有评论SELECT * FROM comments WHERE movie_id = :movie_id ORDER BY comment_creation_datetime DESC,然后递归回显它们。

我尝试了一堆foreach循环,但没有一个按预期工作

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 }

我的问题:

如何使用foreach循环以嵌套的Reddit样式回显注释?

3 个答案:

答案 0 :(得分:2)

我会使用一些递归函数,你从parent_id == 0开始,并递归打印所有直接孩子。

此代码未经过测试,但您可以理解:

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);
    }
}

答案 1 :(得分:2)

使用邻接列表模型对SQL来说可能更成问题。您需要使用单个查询检索所有行,并将任何父项子项的引用存储在查找表中。

$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'];
}

现在您可以使用

显示它们
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>';
        }
    }
}

示例:

// 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);

答案 2 :(得分:2)

您需要制作根评论列表,并按层次结构组织所有评论。你可以一气呵成:

$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);

您按日期对列表进行了预先排序,这是在此方法中保留的。此外,由于您只是通过引用重新组织,这是快速闪电,并准备用于模板引擎或任何东西 - 无需像其他答案那样打印内联。