Построение иерархического дерева, на примере вывода древовидных комментариев
В одной из прошлых статей «Построение иерархического дерева. Рекурсивная функция» я уже рассказывал о построении иерархического дерева. В сегодняшней статье я покажу Вам еще один очень интересный способ вывода иерархического дерева или древовидной структуры. А чтобы было нагляднее, я решил показать Вам, как можно организовать вывод древовидных комментариев. Обращаю Ваше внимание, что в этой статье будет затронут ТОЛЬКО ВЫВОД древовидных комментариев и не будет освещаться вопрос добавления комментариев, и все что с этим связано.
Почему именно древовидные комментарии? Да потому что они встречаются практически на каждом блоге, вот я и решил рассказать Вам, как же они устроены.
Первое с чего следует начать, так это с организации структуры базы данных, для хранения древовидной структуры. Структура наших древовидных комментариев ничем не будет отличаться от структуры, о которой я рассказывал в прошлой статье. Разве что у нас появятся дополнительные колонки.
Итак, наша таблица в базе данных будет иметь следующие поля:
- id – уникальный идентификатор комментария
- parent_id – id родительского комментария
- post_id – id роста, к которому относится комментарий
- author – Имя автора комментария
- comment – текст комментария
- addtime - время добавления комментария в UNIX-формате
Для того, чтобы создать такую таблицу в своей базе данных, необходимо выполнить следующий SQL-запрос:
CREATE TABLE IF NOT EXISTS `comments` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`parent_id` int(11) NOT NULL,
`post_id` int(11) NOT NULL,
`author` varchar(255) NOT NULL,
`comment` text NOT NULL,
`addtime` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
Итак, с базой данных разобрались. Переходим к html разметке. Древовидные комментарии удобно выводить в виде ul-списка. Поэтому наша разметка будет выглядеть следующим образом:
<div class="comments_wrap"> <ul> <li> <div class="comment"> <div class="author"> Имя <span class="date">дата</span> </div> <div class="comment_text">комментарий 1</div> </div> <ul> <li> <div class="comment"> <div class="author"> Имя <span class="date">дата</span> </div> <div class="comment_text">комментарий 2</div> </div> </li> </ul> </li> </ul> </div>
Разметка очень простая. CSS стили тоже:
div.comments_wrap{ width: 600px; margin: 0 auto; } div.comments_wrap ul { list-style-type: none; } div.comments_wrap ul li { margin: 7px 0 7px 7px; } div.comments_wrap ul li div.comment { border: solid 1px #ccc; padding: 5px 10px; } div.comments_wrap ul li div.author { font-weight: bold; margin: 3px 0; } div.comments_wrap ul li div.author span.date { padding-left: 20px; } div.comments_wrap ul li div.comment_text { overflow: auto; }
Так, с HTML-разметкой разобрались. Переходим к самому интересному – выводу древовидных комментариев.
Первое что нужно сделать – это установить связь с базой данных. Для работы с базой данных я использую самый простой класс, для работы с базой данных MySQL – DB.class.php. Я о нем уже неоднократно рассказывал в прошлых статьях, поэтому сегодня останавливаться на нем не буду.
Итак, для того чтобы соединиться с базой данных и выбрать нужную БД, необходимо написать следующее:
/* Конфигурация базы данных. Добавьте свои данные */ $dbOptions = array( 'db_host' => 'localhost', 'db_user' => 'user', 'db_pass' => 'pass', 'db_name' => 'db' ); require "DB.class.php"; //Подключаем класс для работы с базой данных
// Соединение с базой данных DB::init($dbOptions);
Все с базой данных мы соединились. Теперь напишем простой SQL-запрос и выберем все комментарии для поста с идентификатором ID = 10 (в реальном приложении идентификатор поста нужно извлекать из GET запроса):
$result = DB::query("SELECT * FROM site_comments WHERE post_id = 10");
Теперь сформируем массив, который будет содержать все комментарии указанного поста:
$_comments = array(); while($row = $result->fetch_assoc()){ $_comments[$row['com_id']] = $row; }
Обращаю Ваше внимание, что в качестве ключа, массива $_comments, выступает идентификатор комментария. Это очень важно, для дальнейшей реализации иерархического дерева комментариев.
Следующим шагом, мы преобразуем этот массив таким образом, что комментарии-ответы (потомки) будут находиться внутри своего родителя, сейчас же все комментарии в массиве находятся независимо друг от друга.
Для того, чтобы это сделать, нам понадобятся вспомогательные функции. Я решил их вынести в отдельный файл helper.php. Поэтому следующим этапом нужно создать этот файл и подключить к нашей странице следующим образом:
require "helper.php"; //Подключаем вспомогательные функции
Итак, основная функция, которая будет отвечать за преобразование массива будет называться build_tree() и выглядит она следующим образом:
/** * Функция для формирования иерархического дерева */ function build_tree($data){ $tree = array(); foreach($data as $id => &$row){ if(empty($row['parent_id'])){ $tree[$id] = &$row; } else{ $data[$row['parent_id']]['childs'][$id] = &$row; } } return $tree; }
Весь секрет данной функции заключается в том, что некоторые значения переменных здесь передаются по ссылке (&$row), а не по значению. За это отвечает символ &. Это очень сложная тема для понимания, которая требует отдельной статьи. Поэтому не будем вдаваться в подробности, главное, что эта функция работает.
Давайте преобразуем массив $_comments используя функцию выше.
$comments = build_tree($_comments); unset($_comments);
После того, как мы сформировали нужный нам массив, осталось вывести само дерево комментариев на экран.
Для этого мы создадим еще одну вспомогательную функцию getCommentsTemplate(), которая будет отвечать за вывод комментариев.
function getCommentsTemplate($comments){ $html = ''; foreach($comments as $comment){ ob_start(); include 'comments_template.php'; $html .= ob_get_clean(); } return $html; }
Основной задачей данной функции является подключения шаблона комментариев comments_template.php. Мы в цикле проходимся по массиву $comments подключая шаблон комментариев для каждого комментария, а чтобы при этом не происходил вывод этого шаблона на экран, мы включаем буферизацию вывода и содержимое буфера присваиваем переменной $html.
Давайте теперь взглянем на код самого шаблона комментариев comments_template.php.
<li> <div class="comment"> <div class="author"> <?php echo $comment['author'];?> <span class="date"><?php echo date('d.m.Y H:i',$comment['addtime']);?></span> </div> <div class="comment_text"><?php echo $comment['comment];?></div> </div> <?php if(!empty($comment['childs'])):?> <ul> <?php echo getCommentsTemplate($comment['childs']);?> </ul> <?php endif;?> </li>
Это самый обычный шаблон, где выводится информация по комментарию и если есть потомки $comment['childs'], мы заново вызываем функцию getCommentsTemplate(). Получается вот такой вот рекурсивный вызов этой функции. Используя данный подход, мы пройдемся по всем комментариям, не зависимо от уровня вложенности и выведем их на экран.
Осталось применить эту функцию к нашему массиву комментариев:
$comments = getCommentsTemplate($comments);
Теперь переменная $comments содержит HTML-код дерева комментариев.
Осталось его вставить в нужное место на нашей странице. Делается это так:
<div class="comments_wrap"> <ul> <?php echo $comments;?> </ul> </div>
Ну вот и все! В данном уроке я рассказал Вам об еще одном способе построения иерархических деревьев в PHP с использованием MySQL.
Если что-то не понятно, задавайте свои вопросы в комментариях ниже и не забудьте поделиться данным уроком со своими друзьями в соц. сетях. Спасибо!
-
Комментарии (10)
- Сайт