PHP: И снова деревья

Не давно была необходимость написать «вложенные» комментарии, к сайту.
Ранее уже сталкивался с этим и даже не задумывался о нагрузке на сервер.
И ведь многие когда реализуют древовидные комментарии или навигацию об этом даже не задумываются?

А что если, в один прекрасный день настанет такой момент что на Вашем блоге напишут 1000 комментариев к одному посту? Возможны несколько вариантов, самый удачный это тот вариант когда Вы будите готовы к этому.
я решил попробовать отдать половину работы серверу СУБД (у меня MySQL), а именно сократить число обращений в нее и считать вложенные комментарии внутри базы выдавая их количество.
Не спорю существует много вариантов это осуществить, и практически все они построены на дополнительных классах либо на дополнительных таблицах, либо же на полях — еще часто их называют level
и т.д.
Ну в общем, вот что у меня получилось:

таблица комментариев comments будет иметь 5 полей:
id(INT)
parent_id(INT)
comment(TEXT)
date(TIMESTAMP)
user(int)

и таблица пользователей user нам хватит и трех:
id(INT)
login(INT)
password(TEXT)

далее одна единственная функция которая и будет выполнять всю работу за нас:

<?
function getComments($id, $parent = 0)
{
$id = (int)$id;
$query = mysql_query("
SELECT `comments_list`.*,
`users`.`login` as `login`,
(SELECT COUNT(`counts`.`id`) FROM `comments` `counts`
WHERE `counts`.`parent` = `comments_list`.`id`) AS `count`,
DATE_FORMAT(`comments_list`.`date`, '%d.%m.%Y %H:%i') as `date`
FROM `comments` `comments_list`
LEFT JOIN `users` ON `comments_list`.`user` = `users`.`id`
WHERE `comments_list`.`news` = '".$id."' AND `comments_list`.`parent` = '".$parent."'");
$i=0;
$comments = false;
while ($comment = mysql_fetch_object($query))
{
$comments[$i] = $comment;
if ($comment->count)
{
$comments[$i]->comments = getComments($id, $comment->id);
}
$i++;
}
return $comments;
}
?>

как видите основная (большая) часть кода — это запрос в СУБД
А сделал я этим запросов следующее:
выбрал из таблицы comments все записи, но сначала сделал алиас (виртуальное имя) для нее, чтобы спокойно выполнить подзапрос в нее же.
выбрал login из таблицы users присоединив его с помощью LEFT JOIN к таблицы comments далее в фильтре WHERE указал что эти комментарии от новости с $id, который приняла функция в первом аргументе, отформатировал дату перед выводом из базы, опять же, чтобы меньше оставлять работы скрипту.
ну и конечно подзапросом SELECT COUNT(`counts`.`id`) FROM `comments` `counts`
WHERE `counts`.`parent` = `comments_list`.`id`) AS `count`
, выбрал количество комментариев, которые вложены к данному комментарию и назвал это количество count

ну и затем уже в цикле while перебирая комментарии, не стал обращаться в базу данных по пусту, заранее зная, что комментариев вложенных нет.
и в итоге введя:
$comments = getComments($id); // ID новости из блога

я получу такой массив:

  1. [0]
    1. [0]
    2. [1]
      1. [0]
      2. [1]
    1. [0]
    2. [1]
    и так можно рисовать до бесконечности, если конечно хватит ресурсов сервера 🙂
    удачи.

http://habrahabr.ru/sandbox/25447/

Share