Посмотрите на:
человек 3 следа
И:
#include <exeinfo.h>
int backtrace(void **buffer, int size);
Это расширения GNU.
Я решил добавить столбец parent_id в базу данных и вместо того, чтобы присоединяться к ответам, я просто выделил все комментарии сразу, чтобы позже отсортировать комментарии и ответы на стороне сервера код, вот запрос:
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
Теперь я передаю результат запроса в функцию ниже, так что каждый ответ будет добавлен в виде массива внутри массива комментариев, поэтому в основном он возвращает многомерный массив.
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;
}
Если вы хотите, чтобы люди могли отвечать на ответы (т. Е. Иметь иерархию ответов, такую как, например, на форуме сетевых сообщений), я бы добавил необязательный parent_comment_id в таблице комментариев.
Ваша таблица будет выглядеть так
`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 ;`
Ваш запрос, в котором будут показаны все комментарии и ответы, будет выглядеть примерно так:
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
Обратите внимание, однако, что с этим запросом ваши ответы также будут отображаться не только в «ответить», но также и в столбце «комментарий» в виде дополнительных строк, каждая из которых содержит ноль или более ответов.
Чтобы отобразить имена пользователей, ответивших на комментарий, вам нужно будет дважды присоединиться к таблице пользователей ( сначала для пользователя, который разместил исходный комментарий, и снова для пользователя (ов), который ответил). Попробуйте этот запрос, чтобы показать имена пользователей, которые ответили:
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
Добавьте столбец parent_comment_id
в таблицу комментариев. Сделайте это необязательным. При запросе вы можете присоединить все дочерние комментарии к каждому родительскому элементу. В качестве небольшой выборочной денормализации (небольшая избыточность) вы можете убедиться, что topic_id
также установлен для дочерних комментариев, что позволит вам вытащить их все немного проще (при условии, что вы собираетесь отображать все дочерние комментарии в основной поток комментариев, а не через более мелкие запросы ajax).
Создайте презентацию, как вам нужно, закиньте результаты в memcached (или в плоский файл, или в память ... как бы вы ни кешировали), и все готово.
Ответ на комментарий - это комментарий с родительским comment_id. Попробуйте добавить comment_id в качестве поля в таблицу комментариев. Вы получите древовидную структуру.
Если вы хотите получить все дерево комментариев, лучше всего использовать вложенный набор ( https: //wiki.htc.lan/Hierarchy_model ). Но это более сложное решение.
Вот дополнительная информация из MySQL: http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/
Похоже, вы работаете с WordPress, добавление parent_comment_id
было бы идеальным решением, но не в этом случае.
Во-первых, я не думаю. изменение основных таблиц WordPress - хорошая идея. Во-вторых, вы получите сложный код, который сломается с обновлениями wordpress.
Лучше всего использовать такой плагин, как Intense Comments
Тем не менее, если вы хотите создать свое собственное решение, я бы сказал создать другая таблица для ответов на комментарии. a) Ваша новая таблица будет выглядеть так
`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) Вы получите их таким образом
$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) Теперь в цикле комментариев вы можете получать такие ответы
foreach ( $replies_by_parent [$parent_id] as $reply ) {
echo $reply->comment;
}
Кажется, все в порядке, но что делать, если таблица содержит более миллиона строк? а некоторые комментарии могут быть разделены сотнями тысяч строк. как будут выполняться эти запросы?