微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

php – 多层评论回复:显示和存储

所以我正在尝试创建一个评论系统,您可以在其中回复已经回复评论(允许您创建理论上无限的回复帖子).我希望它们按时间顺序显示(最新的),但当然回复应该直接在原始评论下面.如果有多条评论回复同一条评论,则回复也应按时间顺序排列(仍在原评论的下方).我还想限制评论组的数量(一组评论只有一个评论,而不是一个回复),比方说,25.我应该如何设置MySQL表,以及我将使用哪种查询提取我想要的东西?

这是我的数据库的简化版本:
ID int(11)NOT NULL AUTO_INCREMENT,
DatePosted datetime NOT NULL,
InReplyTo int(11)NOT NULL DEFAULT’0′,

对不起,如果这有点令人困惑,我不知道如何以不同的方式说出来.我脑子里已经有这个问题了几个月了,每当我解决一个问题时,我最终会得到另一个……

解决方法:

有很多方法.这是我喜欢的一种方法(并定期使用).

数据库

考虑以下数据库结构:

CREATE TABLE comments (
  id int(11) unsigned NOT NULL auto_increment,
  parent_id int(11) unsigned default NULL,
  parent_path varchar(255) NOT NULL,

  comment_text varchar(255) NOT NULL,
  date_posted datetime NOT NULL,  

  PRIMARY KEY  (id)
);

您的数据将如下所示:

+-----+-------------------------------------+--------------------------+---------------+
| id  | parent_id | parent_path             | comment_text             | date_posted   |
+-----+-------------------------------------+--------------------------+---------------+
|   1 | null      | /                       | I'm first                | 1288464193    | 
|   2 | 1         | /1/                     | 1st Reply to I'm First   | 1288464463    | 
|   3 | null      | /                       | Well I'm next            | 1288464331    | 
|   4 | null      | /                       | Oh yeah, well I'm 3rd    | 1288464361    | 
|   5 | 3         | /3/                     | reply to I'm next        | 1288464566    | 
|   6 | 2         | /1/2/                   | this is a 2nd level reply| 1288464193    | 

... and so on...

以可用的方式选择所有内容相当容易:

select id, parent_path, parent_id, comment_text, date_posted
from comments 
order by parent_path, date_posted;

按parent_path排序,date_posted通常会在您生成页面时按照您需要的顺序生成结果;但是你要确保你在评论表上有一个正确支持这个的索引 – 否则查询会起作用,但它确实非常低效:

create index comments_hier_idx on comments (parent_path, date_posted);

对于任何给定的单一评论,很容易得到该评论的整个儿童评论树.只需添加一个where子句:

select id, parent_path, parent_id, comment_text, date_posted
from comments 
where parent_path like '/1/%'
order by parent_path, date_posted;

添加的where子句将使用我们已经定义的相同索引,所以我们很高兴.

请注意,我们还没有使用parent_id.事实上,它并非绝对必要.但我包含它是因为它允许我们定义传统的外键来强制引用完整性并在我们想要时实现级联删除和更新.外键约束和级联规则仅在INNODB表中可用:

ALTER TABLE comments ENGINE=InnoDB;

ALTER TABLE comments 
  ADD FOREIGN KEY ( parent_id ) REFERENCES comments 
    ON DELETE CASCADE 
    ON UPDATE CASCADE;

管理层次结构

当然,为了使用这种方法,您必须确保在插入每个注释时正确设置parent_path.如果你移动评论(这肯定是一个奇怪的用例),你必须确保你手动更新从属于移动的评论的每个评论的每个parent_path. ……但这些都是相当容易跟上的事情.

如果你真的想要得到它(并且如果你的数据库支持它),你可以编写触发器来透明地管理parent_path – 我将为读者留下一个练习,但基本的想法是插入和更新触发器会触发在提交新插入之前.它们将沿树向上移动(使用parent_id外键关系),并相应地重建parent_path的值.

甚至可以将parent_path分解为一个单独的表,该表完全由注释表上的触发器管理,具有一些视图或存储过程来实现您需要的各种查询.因此,完全隔离您的中间层代码,而不需要了解或关心存储层次结构信息的机制.

当然,通过任何方式都不需要任何花哨的东西 – 通常只需将parent_path删除到表中,并在中间层中编写一些代码以确保它与所有其他字段一起正确管理你必须要管理.

施加限制

MysqL(以及其他一些数据库)允许您使用LIMIT子句选择数据的“页面”:

SELECT * FROM mytable LIMIT 25 OFFSET 0;

不幸的是,在处理这样的分层数据时,LIMIT子句本身不会产生预期的结果.

-- the following will NOT work as intended

select id, parent_path, parent_id, comment_text, date_posted
from comments 
order by parent_path, date_posted
LIMIT 25 OFFSET 0;

相反,我们需要在我们想要施加限制的级别上进行单独的选择,然后我们将其与我们的“子树”查询一起加回以给出最终期望的结果.

像这样的东西:

select 
  a.*
from 
  comments a join 
  (select id, parent_path 
    from comments 
    where parent_id is null
  order by parent_path, post_date DESC 
  limit 25 offset 0) roots
  on a.parent_path like concat(roots.parent_path,roots.id,'/%') or a.id=roots.id)
order by a.parent_path , post_date DESC;

注意声明限制25偏移0,埋在内部选择的中间.此语句将检索最新的25个“根级”注释.

[编辑:你可能会发现你需要玩一些东西来获得按照自己喜欢的方式订购和/或限制事物的能力.这可能包括在parent_path中编码的层次结构中添加信息.例如:代替/ {id} / {id2} / {id3} /,您可能决定将post_date包含在parent_path的一部分中:/ {id}:{post_date} / {id2}:{post_date2} / { ID3}:{post_date3} /.这样可以很容易地获得所需的订单和层次结构,代价是必须预先填充字段,并在数据更改时对其进行管理]

希望这可以帮助.
祝好运!

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐