Построение дерева категорий на PHP. Рекурсия
Сегодня я расскажу, как на PHP и MySQL создавать иерархическое дерево.
Такие деревья используются при построении категорий динамического сайта, например в интернет-магазине или при выводе комментариев к посту.
Вообще они строятся где только возможно. Главное правильно его построить и применить.
Самое главное, когда строишь иерархическое дерево — это правильная структура базы данных! Для примера рассмотрим структуру базы данных, где хранятся категории сайта. Для простого примера, таблица будет иметь 3 поля:
- id — ключ категории
- parent_id — id родительской категории
- name – название раздела
Создадим таблицу, выполнив SQL-запрос в PHPMyAdmin:
CREATE TABLE `categories` ( `id` INT NOT NULL AUTO_INCREMENT , `parent_id` INT NOT NULL , `name` VARCHAR( 50 ) NOT NULL , PRIMARY KEY ( `id` ) );
Теперь нужно заполнить нашу таблицу записями. В результате, должна получится примерно такая таблица:
Можно заполнить тестовую таблицу запросом:
INSERT INTO `categories` (`id`, `parent_id`, `name`) VALUES (1, 0, 'Раздел 1'), (2, 0, 'Раздел 2'), (3, 0, 'Раздел 3'), (4, 1, 'Раздел 1.1'), (5, 1, 'Раздел 1.2'), (6, 4, 'Раздел 1.1.1'), (7, 2, 'Раздел 2.1'), (8, 2, 'Раздел 2.2'), (9, 3, 'Раздел 3.1');
С базой данных всё! Дальше идем к формированию самого дерева разделов.
И сейчас внимание! Дальше по логике нужно делать выборки из БД в цикле для выбора каждой категории и её подкатегории. НО! Ладно, если в БД несколько категорий, что тоже в принципе не правильно. А если сайт — интернет-магазин и у него сотня категорий и столько же подкатегорий? Тогда беда! Неведомое количество запросов к базе данных приведет к замедлению работы сайта или же к полному краху mysql-сервера.
Можно используя только один запрос к БД выбрать все категории и ихние подкатегории.
Сделаем запрос и сформируем удобный массив для дальнейшей работы.
//Выбираем данные из БД $result=mysql_query("SELECT * FROM categories"); //Если в базе данных есть записи, формируем массив if (mysql_num_rows($result) > 0){ $cats = array(); //В цикле формируем массив разделов, ключом будет id родительской категории, а также массив разделов, ключом будет id категории while($cat = mysql_fetch_assoc($result)){ $cats_ID[$cat['id']][] = $cat; $cats[$cat['parent_id']][$cat['id']] = $cat; } }
Выбираем все данные из таблицы categories и формируем ассоциативный массив $cats, ключем будет id родительской категорий.
Сейчас будем строить дерево. Для построения будем использовать рекурсивную функцию.
Иерархическое дерево будет иметь такую структуру:
<ul> <li>Раздел 1 <ul> <li>Раздел 1.1 <ul> <li>Раздел 1.1.1</li> </ul> </li> <li>Раздел 1.2</li> </ul> </li> <li>Раздел 2 <ul> <li>Раздел 1.1</li> <li>Раздел 1.2</li> </ul> </li> <li>Раздел 3 <ul> <li>Раздел 3.1</li> </ul> </li> </ul>
Создадим рекурсивную функцию build_tree(). Она будет строить наше иерархическое дерево абсолютно любой вложенности.
function build_tree($cats,$parent_id,$only_parent = false){ if(is_array($cats) and isset($cats[$parent_id])){ $tree = '<ul>'; if($only_parent==false){ foreach($cats[$parent_id] as $cat){ $tree .= '<li>'.$cat['name'].' #'.$cat['id']; $tree .= build_tree($cats,$cat['id']); $tree .= '</li>'; } }elseif(is_numeric($only_parent)){ $cat = $cats[$parent_id][$only_parent]; $tree .= '<li>'.$cat['name'].' #'.$cat['id']; $tree .= build_tree($cats,$cat['id']); $tree .= '</li>'; } $tree .= '</ul>'; } else return null; return $tree; }
Функция принимает массив разделов и id раздела. В цикле перебираем подкатегории и если в них есть еще разделы, тогда функция запускается еще раз с новыми параметрами (новый массив разделов и id раздела, который нужно построить). Так формируется дерево любой вложенности!
Для построения дерева, в коде прописываем:
echo build_tree($cats,0);
Так вот в два шага мы создали иерархическое дерево разделов сайта и не важно сколько там разделов!
UPD Если нужно дерево категорий в обратном порядке зная id категории, тогда нужно воспользоваться функцией:
function find_parent ($tmp, $cur_id){ if($tmp[$cur_id][0]['parent_id']!=0){ return find_parent($tmp,$tmp[$cur_id][0]['parent_id']); } return (int)$tmp[$cur_id][0]['id']; }
Данная функция принимает массив категорий, ключом которой есть id рубрики, и id категории от которой нужно идти вверх.
Для построения такого дерева запускаем функцию build_tree c такими параметрами:
echo build_tree($cats,0,find_parent($cats_ID,ВАШ_ID_КАТЕГОРИИ));
Есть вопросы? Задавайте в комментариях
Сергей
17:12 28.10.2012А как в данном случае будет выглядеть код для select? Чтобы все загружалось в Select, и желательно чтобы были optgroup