I\'ve been thinking about this one for quite some time now, I need a way to add replies to comments in the database but I\'m not sure how to proceed.
This is my curr
Add a parent_comment_id
column to your comments table. Make it optional. When you query, you can join all child comments to each parent. As a bit of selective denormalization (slight redundancy) you can make sure topic_id
is set on the child comments as well, letting you pull them all a bit easier (assuming you're going to display all child comments in the main comment thread and not via smaller ajax requests).
Build the presentation however you need, toss the results into memcached (or a flat file, or memory... however you're caching) and you're set.
I decided to add the parent_id column in the database and instead of left joining the replies I just selected all the comments at once to later on sort the comments and replies with server-side code, heres the query:
SELECT c.*, u.username, u.photo
FROM (comments c)
JOIN users u ON c.user_id = u.id
WHERE c.topic_id = 9
ORDER BY c.id ASC
Now I pass the query result to the below function so that every reply will be added as an array inside the comment array, so basically it returns a multidimensional array.
function sort_comments($ar)
{
$comments = array();
foreach($ar as $item)
{
if(is_null($item['parent_id'])) $comments[] = $item;
else
{
$parent_array = array_search_key($item['parent_id'],$comments,'id');
if($parent_array !== false) $comments[$parent_array]['replies'][] = $item;
}
}
return $comments;
}
If you want people to be able to reply to the replies (i.e. have a hierarchy of replies such as you would see in, say, an online message forum), then I would add an optional parent_comment_id field to the comments table.
Your table would look like this
`CREATE TABLE IF NOT EXISTS `comments` (
`id` int(12) NOT NULL AUTO_INCREMENT,
`parent_comment_id` int(12) NULL,
`comment` text,
`user_id` int(12) DEFAULT NULL,
`topic_id` int(12) NOT NULL,
`ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`),
KEY `topic_id` (`topic_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=27 ;`
Your query showing all comments and replies would be something like:
SELECT c.id, c.comment, r.comment as reply, c.user_id, u.username, u.photo
FROM (comments c)
JOIN users u ON c.user_id = u.id
LEFT JOIN comments r ON c.id = r.parent_comment_id
WHERE c.topic_id = 9
Note however that with this query your replies would also show up not only in the 'reply' column, but also in the 'comment' column as additional rows each with zero or more replies.
To show the username of the users who replied to a comment, you will need to join twice to the users table (first for the user who posted the original comment, and again for the user(s) who replied). Try this query to show the usernames of the users who replied:
SELECT c.id, c.comment, c.user_id, u.username, u.photo, r.comment as reply, r.user_id as reply_user_id,
u2.username as reply_username, u2.photo as reply_photo
FROM (comment c)
JOIN users u ON c.user_id = u.id
LEFT JOIN comments r ON c.id = r.parent_comment_id
JOIN users u2 ON r.user_id = u2.id
WHERE c.topic_id = 9
A comment reply is a comment with a parent comment_id. Try adding comment_id as a field to your comments table. What you will get is a tree-like structure.
If you wish to retrieve an entire tree of comments, your best bet is to use a nested set (https://wiki.htc.lan/Hierarchy_model). But that's a more complicated solution.
Here's some more info from MySQL: http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/
function sort_comments($ar)
{
$comments = [];
$i=0;
foreach($ar as $co){
if(!empty($co['comment_replyof'])) {
$comments[$co['comment_replyof']]['replies'] = $co;
}else{
foreach($co as $c => $o) $comments[$co['comment_id']][$c] = $o;
}
$i++;
}
return $comments;
}
SELECT C.*, U.id,U.fname, U.lname FROM (comment C) JOIN users U ON `enter code here`C.comment_user = U.id where C.comment_content='10'
Looks like you are working with WordPress, adding a parent_comment_id
would have been an ideal solution, but not in this case.
Firstly, I don't think modifying the WordPress basic tables is a good idea. Secondly, you'll end-up with a complex code that will break with wordpress updates.
Best is use a plugin like Intense Comments
Still if you want to create your own solution, I would say create another table for comment replies. a) Your new table would look like this
`CREATE TABLE IF NOT EXISTS `comment_replies` (
`id` int(12) NOT NULL AUTO_INCREMENT,
`parent_comment_id` int(12) NULL,
`comment` text,
`user_id` int(12) DEFAULT NULL,
`topic_id` int(12) NOT NULL,
`ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`),
KEY `topic_id` (`topic_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
b) You'd fetch them this way
$comment_ids = array_map( 'intval', array_keys( $comments ) );
sort( $comment_ids );
$comments_id_list = join( ',', $comment_ids );
$query = "SELECT c.id, c.comment, c.user_id, u.username, u.photo
FROM (comment_replies c)
JOIN users u ON c.user_id = u.id
WHERE c.parent_comment_id IN ( $comments_id_list )"
$replies = $wpdb->get_results($query);
$replies_by_parent = array();
foreach ( array_keys( $replies ) as $i ) {
$replies_by_parent [$replies[$i]->id] = array();
}
foreach ( array_keys( $replies ) as $i ) {
$replies_by_parent [$replies[$i]->id][] =& $replies[$i];
}
c) Now within your comments loop you can get the replies like this
foreach ( $replies_by_parent [$parent_id] as $reply ) {
echo $reply->comment;
}