Discuz! 嵌套回复实现

最近支援一个项目,采用discuz!程序,需要实现嵌套回复,效果类似WordPress的效果,某条回复的回复需要排在一起显示。

嵌套回复效果

没有使用discuz!的点评功能,而是通过改造post表实现嵌套功能。

数据库结构

在discuz!的post表增加字段:

alter table pre_forum_post add parentid int(10) unsigned NOT NULL DEFAULT '0',topid int(10) unsigned NOT NULL DEFAULT '0';

- parentid 父级回复id
- topid 根回复id

添加回复

- 需要传递父级回复pid.
- 如果是根回复,parentid = 0,topid = 0.
- 如果是子回复,parentid = 父级回复的pid,topid = 父级回复的topid. 父级回复的pid和topid需要根据传递的pid进行查询.

查询一个回复下的所有嵌套回复

取一个根回复下的所有子回复,执行sql:

select * from pre_forum_post where toppid = xxx order by qpid desc, pid desc;

php处理成树形结构。

// $rows 为执行上述sql的查询结果
foreach ($rows as $k => $row) {
    if ($row['toppid'] == $row['parentid']) {
        $key = $row['parentid'] . '-' . $row['pid'];
    } else {
        $key = $map[$row['parentid']] . '-'. $row['pid'];
    }
    $map[$k] = $key;
}

ksort($map);
// 排序后的结果:
// 1
// 1-4
// 1-4-7
// 1-5
// 1-2

foreach ($map as $pid) {
   $result[$pid] = $rows[$pid];
}
// result 即为排序好后的回复列表

缓存

- 对所有topid的嵌套回复建立缓存。
pid => array(), array()中存储其下所有嵌套回复。
- 列表页直接查询缓存显示。

缺点

- 更新时触发缓存更新,需要一次取出topid下的所有回复进行php排序处理。
- 回复过多时,缓存过大或无法缓存。

其他

- 因为项目需求特殊,一条回复的嵌套回复只显示前50条,所以缓存不会太大。上面这种方案应该可以满足需求,但是需要考虑查询如何优化。
- 网上搜索了相关的资料,也没有找到太合适的方案。网上的方案是取出数据后进行递归遍历,后续比较下两种方式的效率差别。

参考资料

- 无限分类设计方案 http://www.ccvita.com/315.html
- 在数据库中存储层次数据 http://shiningray.cn/hierarchical-data-database.html

标签: Discuz

已有 11 条评论

  1. peng peng

    我跟你的思路一样的数据库加了两个字段,我的问题是dz的源代码,和模板你怎么修改的啊,能否把你修改dz的文件发到我邮箱啊

    1. Don Don

      前端已经不是用discuz模板实现了,最简单的就是按discuz模板一样一条一条回复的展示,如果需要显示嵌套效果,可以参考wordPress模板吧

      1. dearc dearc

        请问后台数据库是递归查询的吗

        1. Don Don

          一次性查出所有评论,然后PHP进行排序。

  2. peng peng

    这个问题解决了,我遇到一个新的问题,做的一个插件回复帖子,有时候会出现通过插件的url回的帖子,插入post表了,但是论坛没显示,然后再通过dz的正常回复帖子回复后,然后就正常显示了

    1. Don Don

      你试试直接往post表添加一条记录,论坛前台会显示出来吗?
      感觉可能是少写了其他表了

  3. iamatig iamatig

    能否提供下升级包?
    不太熟悉这些操作,谢谢

  4. jackyshaw jackyshaw

    id topid parentid
    4 1 1
    7 1 4

    我怎么觉得你代码写的有问题

    1. Don Don

      哪里呢?

    2. jackyshaw jackyshaw

      $rows[$row['parentid']]这里取的是什么鬼 我请问 $rows是所有子回复的列表集合哦 按你的sql语句写的

      如果拿 4 1 1这条记录来说的话 if ($row['topid']) {
      $key = (string)$row['pid'];
      } else {
      $key = $rows[$row['parentid']] . '-' . $row['pid']; // 1-4, 1-4-7
      }

      $map[$key] = $row['pid'];

      这条记录的运行结果是$map[4]=4;

      这是对的么,还是我老花

      1. Don Don

        思路就是按toppid - parentid - pid 拼数组key,然后通过php进行数组排序实现的。

        为了你这个回复我又特意去看了眼这项目的代码,已经修改了。

添加新评论