Древовидные комментарии с использованием модели Nested Sets
Вывод комментариев в древовидной структуре используя модель хранения вложенных сильев Nested Sets.
От автора:
Многие по наивности полагают что настоящая задача больно сложная, не буду их разубеждать, вот решение какое было ввергнуто в бытие за два с половиной часа воскресным ввечеру.
Для решения задачи использовать будем класс dbtree
0.
0. Выполняем sql запросы:
LTER TABLE `dle_comments`
ADD `ns_level` INT(11) DEFAULT NULL;
ALTER TABLE `dle_comments`
ADD `ns_right` BIGINT(20) NOT NULL DEFAULT 0;
ALTER TABLE `dle_comments`
ADD `ns_left` BIGINT(20) NOT NULL DEFAULT 0;
1. Файл: show.full.php - изменяем запрос для получения комментариев:
$comments->query = "SELECT " . PREFIX . "_comments.id,
post_id, " . PREFIX . "_comments.user_id, date, autor as gast_name,
" . PREFIX . "_comments.email as gast_email, text, ip, is_register, name,ns_level, " . USERPREFIX . "_users.email, news_num, comm_num, user_group, reg_date, signature, foto, fullname, land, icq, xfields FROM " . PREFIX . "_comments
LEFT JOIN " . USERPREFIX . "_users ON " . PREFIX . "_comments.user_id=" . USERPREFIX . "_users.user_id
WHERE " . PREFIX . "_comments.post_id = '$news_id'" . $where_approve . " ORDER BY " . PREFIX . "_comments.ns_right DESC ";
2. Файл: comments.class.php - убираем лимит из запроса
#Было
#$sql_result = $this->db->query($this->query . " LIMIT " . $this->cstart . "," . $this->comments_per_pages);
#Стало
$sql_result = $this->db->query($this->query);
3.Файл: modules/addcomments.php - изменяем добавление комментариев с учетом новых требование.
// перед
//if ($update_comments) {
//добавляем
$_ns_id = (int) $_REQUEST['ns_parent_id'];
if ($_ns_id)
$update_comments = false;
//после $comments = $db->safesql($comments);
//добавляем
require_once ROOT_DIR . '/engine/classes/dbtree/db_mysql.class.php';
require_once ROOT_DIR . '/engine/classes/dbtree/dbtree.class.php';
$_db = new _db(DBHOST, DBUSER, DBPASS, DBNAME);
$dbtree = new dbtree(PREFIX . '_comments', 'ns', $_db);
if ($_ns_id) {
$dbtree->Insert($_ns_id, array(
'and' => array('parent_id' => "post_id='" . $post_id . "'")
), array(
'post_id' => $post_id,
'user_id' => $member_id['user_id'],
'date' => $time,
'autor' => $name,
'text' => $comments,
'ip' => $_IP,
'is_register' => 1,
'approve' => $where_approve
));
} else {
if ($is_logged)
$db->query("INSERT INTO " . PREFIX . "_comments
(post_id, user_id, date, autor, email, text, ip, is_register, approve) values
('$post_id', '$member_id[user_id]', '$time', '$name', '$mail', '$comments', '$_IP', '1', '$where_approve')");
else
$db->query("INSERT INTO " . PREFIX . "_comments (post_id, date, autor, email, text, ip, is_register, approve) values ('$post_id', '$time', '$name', '$mail', '$comments', '$_IP', '0', '$where_approve')");
}
//прежние запросы комментируем или удаляем
// if ($is_logged)
// $db->query("INSERT INTO " . PREFIX . "_comments
// (post_id, user_id, date, autor, email, text, ip, is_register, approve) values
// ('$post_id', '$member_id[user_id]', '$time', '$name', '$mail', '$comments', '$_IP', '1', '$where_approve')");
// else
// $db->query("INSERT INTO " . PREFIX . "_comments (post_id, date, autor, email, text, ip, is_register, approve) values ('$post_id', '$time', '$name', '$mail', '$comments', '$_IP', '0', '$where_approve')");
4. Файл: ajax/addcomments.php - добавляем лимит в запрос на получение комментария.
$comments->query = "SELECT " . PREFIX . "_comments.id, post_id, " . PREFIX . "_comments.user_id, date, autor as gast_name,
" . PREFIX . "_comments.email as gast_email, text, ip, is_register, name,
" . USERPREFIX . "_users.email, news_num, comm_num, user_group, reg_date, signature, foto, fullname, land, icq, xfields
FROM " . PREFIX . "_comments LEFT JOIN " . USERPREFIX . "_users
ON " . PREFIX . "_comments.user_id=" . USERPREFIX . "_users.user_id
WHERE " . PREFIX . "_comments.post_id = '$post_id' order by id DESC LIMIT 1";
5. .classes/js/dle_js.js - добавляем функцию отправки ответа.
function add_answer(parent_id){
var button = {};
var a=document.getElementById("dle-comments-form");
if(dle_wysiwyg=="yes"){
document.getElementById("comments").value=$("#comments").html();
var b="wysiwyg"
}else b="";
button[dle_p_send]=function(){
ShowLoading("");
$.post(dle_root+
"engine/ajax/addcomments.php",{
post_id:a.post_id.value,
comments: $('#review').val(),
name:a.name.value,
mail:a.mail.value,
editor_mode:b,
skin:dle_skin,
ns_parent_id: parent_id,
allow_subscribe: '0'
},function(b){
if(a.sec_code)a.sec_code.value="",reload();
HideLoading("");
RunAjaxJS("answer-"+parent_id,b);
b!="error"&&document.getElementById("blind-animation")&&($("html"+(!$.browser.opera?",body":"")).animate({
scrollTop:$("#dle-ajax-comments").offset().top-70
},1100),setTimeout(function(){
$("#blind-animation").show("blind",
{},1500)
},1100))
})
$(this).dialog("close");
};
$("#d-popup").remove();
var div = $('<div id="d-popup" style="display:none"></div>'),
frm = $('<form name="answer"><textarea id="review" rows="6" cols="" name="review" style="width:98%"></textarea></form>')
$("body").append(div);
$(div).append(frm)
$("#d-popup").dialog({
autoOpen: true,
width: 690,
height: 270,
resize:false,
buttons: button,
open: function(){
}
});
}
6. в шаблон cjmments.tpl добавляем уровень вложенности, ссылку на добавление ответа и элемент разметки для размещения вновь добавленного ответа к комментарию.
<div class="bcomment" style="padding-left:{level}0px !important">
.............
<span class="reply"><a href="javascript:add_answer('{id}')"><b>Ответить</b></a></span>
..............
<div id="answer-{id}" style="padding-left:{level}9px !important"></div>
LTER TABLE `dle_comments`
ADD `ns_level` INT(11) DEFAULT NULL;
ALTER TABLE `dle_comments`
ADD `ns_right` BIGINT(20) NOT NULL DEFAULT 0;
ALTER TABLE `dle_comments`
ADD `ns_left` BIGINT(20) NOT NULL DEFAULT 0;
1. Файл: show.full.php - изменяем запрос для получения комментариев:
$comments->query = "SELECT " . PREFIX . "_comments.id,
post_id, " . PREFIX . "_comments.user_id, date, autor as gast_name,
" . PREFIX . "_comments.email as gast_email, text, ip, is_register, name,ns_level, " . USERPREFIX . "_users.email, news_num, comm_num, user_group, reg_date, signature, foto, fullname, land, icq, xfields FROM " . PREFIX . "_comments
LEFT JOIN " . USERPREFIX . "_users ON " . PREFIX . "_comments.user_id=" . USERPREFIX . "_users.user_id
WHERE " . PREFIX . "_comments.post_id = '$news_id'" . $where_approve . " ORDER BY " . PREFIX . "_comments.ns_right DESC ";
2. Файл: comments.class.php - убираем лимит из запроса
#Было
#$sql_result = $this->db->query($this->query . " LIMIT " . $this->cstart . "," . $this->comments_per_pages);
#Стало
$sql_result = $this->db->query($this->query);
3.Файл: modules/addcomments.php - изменяем добавление комментариев с учетом новых требование.
// перед
//if ($update_comments) {
//добавляем
$_ns_id = (int) $_REQUEST['ns_parent_id'];
if ($_ns_id)
$update_comments = false;
//после $comments = $db->safesql($comments);
//добавляем
require_once ROOT_DIR . '/engine/classes/dbtree/db_mysql.class.php';
require_once ROOT_DIR . '/engine/classes/dbtree/dbtree.class.php';
$_db = new _db(DBHOST, DBUSER, DBPASS, DBNAME);
$dbtree = new dbtree(PREFIX . '_comments', 'ns', $_db);
if ($_ns_id) {
$dbtree->Insert($_ns_id, array(
'and' => array('parent_id' => "post_id='" . $post_id . "'")
), array(
'post_id' => $post_id,
'user_id' => $member_id['user_id'],
'date' => $time,
'autor' => $name,
'text' => $comments,
'ip' => $_IP,
'is_register' => 1,
'approve' => $where_approve
));
} else {
if ($is_logged)
$db->query("INSERT INTO " . PREFIX . "_comments
(post_id, user_id, date, autor, email, text, ip, is_register, approve) values
('$post_id', '$member_id[user_id]', '$time', '$name', '$mail', '$comments', '$_IP', '1', '$where_approve')");
else
$db->query("INSERT INTO " . PREFIX . "_comments (post_id, date, autor, email, text, ip, is_register, approve) values ('$post_id', '$time', '$name', '$mail', '$comments', '$_IP', '0', '$where_approve')");
}
//прежние запросы комментируем или удаляем
// if ($is_logged)
// $db->query("INSERT INTO " . PREFIX . "_comments
// (post_id, user_id, date, autor, email, text, ip, is_register, approve) values
// ('$post_id', '$member_id[user_id]', '$time', '$name', '$mail', '$comments', '$_IP', '1', '$where_approve')");
// else
// $db->query("INSERT INTO " . PREFIX . "_comments (post_id, date, autor, email, text, ip, is_register, approve) values ('$post_id', '$time', '$name', '$mail', '$comments', '$_IP', '0', '$where_approve')");
4. Файл: ajax/addcomments.php - добавляем лимит в запрос на получение комментария.
$comments->query = "SELECT " . PREFIX . "_comments.id, post_id, " . PREFIX . "_comments.user_id, date, autor as gast_name,
" . PREFIX . "_comments.email as gast_email, text, ip, is_register, name,
" . USERPREFIX . "_users.email, news_num, comm_num, user_group, reg_date, signature, foto, fullname, land, icq, xfields
FROM " . PREFIX . "_comments LEFT JOIN " . USERPREFIX . "_users
ON " . PREFIX . "_comments.user_id=" . USERPREFIX . "_users.user_id
WHERE " . PREFIX . "_comments.post_id = '$post_id' order by id DESC LIMIT 1";
5. .classes/js/dle_js.js - добавляем функцию отправки ответа.
function add_answer(parent_id){
var button = {};
var a=document.getElementById("dle-comments-form");
if(dle_wysiwyg=="yes"){
document.getElementById("comments").value=$("#comments").html();
var b="wysiwyg"
}else b="";
button[dle_p_send]=function(){
ShowLoading("");
$.post(dle_root+
"engine/ajax/addcomments.php",{
post_id:a.post_id.value,
comments: $('#review').val(),
name:a.name.value,
mail:a.mail.value,
editor_mode:b,
skin:dle_skin,
ns_parent_id: parent_id,
allow_subscribe: '0'
},function(b){
if(a.sec_code)a.sec_code.value="",reload();
HideLoading("");
RunAjaxJS("answer-"+parent_id,b);
b!="error"&&document.getElementById("blind-animation")&&($("html"+(!$.browser.opera?",body":"")).animate({
scrollTop:$("#dle-ajax-comments").offset().top-70
},1100),setTimeout(function(){
$("#blind-animation").show("blind",
{},1500)
},1100))
})
$(this).dialog("close");
};
$("#d-popup").remove();
var div = $('<div id="d-popup" style="display:none"></div>'),
frm = $('<form name="answer"><textarea id="review" rows="6" cols="" name="review" style="width:98%"></textarea></form>')
$("body").append(div);
$(div).append(frm)
$("#d-popup").dialog({
autoOpen: true,
width: 690,
height: 270,
resize:false,
buttons: button,
open: function(){
}
});
}
6. в шаблон cjmments.tpl добавляем уровень вложенности, ссылку на добавление ответа и элемент разметки для размещения вновь добавленного ответа к комментарию.
<div class="bcomment" style="padding-left:{level}0px !important">
.............
<span class="reply"><a href="javascript:add_answer('{id}')"><b>Ответить</b></a></span>
..............
<div id="answer-{id}" style="padding-left:{level}9px !important"></div>
В прикрепленном архиве все необходимое для тестирования.
p.s. класс _db был изменен под использование с mysqlL.
p.s.s. работоспособность образца зависит от прямых рук.
Автор: DG
Теги: Древовидные, комментарии, использованием, модели, Nested, Sets