Ни один сайт не обходится без навигации или как еще называют "меню сайта". Так вот меню сайта бывает одноуровневым и многоуровневым в виде дерева. Если с одноуровневым меню особых сложностей в плане реализации не возникает, то при создании многоуровневого меню нужно хорошо подумать.
Самое главное в этой задаче это спроектировать базу данных для нашего многоуровневого меню. Создадим таблицу Categories с тремя полями id , title , parent где:
- ID – идентификатор
- Title – Название меню
- Parent – Родитель категории по умолчанию 0
За ветвление меню отвечает поле Parent если Parent = 0 , то эта категория является родительской. Для того чтобы добавить потомков к родительской категории нужно в поле parent указать ID нужного родителя. Например:
ID | TITLE | PARENT |
---|---|---|
1 | Автомобили | 0 |
2 | Мотоциклы | 0 |
3 | Мазда | 1 |
4 | Хонда | 1 |
5 | Кавасаки | 2 |
6 | Харлей | 2 |
7 | Лодки | 0 |
Как видно из таблицы, у родительской категории Автомобили есть два потомка – это Мазда и Хонда связанных по полю Parent . А у категории Мотоциклы два потомка – это Кавасаки и Харлей . При этом у категории Лодки нет потомков. Надеюсь, что Вы поняли,как связать категории.
CREATE TABLE IF NOT EXISTS `categories` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`title` varchar(255) NOT NULL,
`parent` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=20 ;
--
-- Дамп данных таблицы `categories`
--
INSERT INTO `categories` (`id`, `title`, `parent`) VALUES
(1, 'Автомобили', 0),
(2, 'Мотоциклы', 0),
(3, 'Мазда', 1),
(4, 'Хонда', 1),
(5, 'Кавасаки', 2),
(6, 'Харлей', 2),
(7, 'Мазда 3', 3),
(8, 'Мазда 6', 3),
(9, 'Седан', 7),
(10, 'Хечбэк', 7),
(11, 'Лодки', 0),
(12, 'Лифтбэк', 8),
(13, 'Кроссовер', 8),
(14, 'Белый', 13),
(15, 'Красный', 13),
(16, 'Черный', 13),
(17, 'Зеленый', 13),
(18, 'Мазда CX', 3),
(19, 'Мазда MX', 3);
- Создаем соединение с базой данных
- Получаем все данные из таблицы Categories
- Обрабатываем полученные данные изменив ключ массива на номер ID
- Из обработанного массива строим дерево зависимостей неограниченной вложенности используя метод рекурсии для построения
- Выводим наше многоуровневое меню на экран
<?php
//Устанавливаем кодировку и вывод всех ошибок
header('Content-Type: text/html; charset=UTF-8');
error_reporting(E_ALL);
//Объектно-ориентированный стиль
$mysqli = new mysqli('localhost', 'user', 'password', 'database');
//Устанавливаем кодировку utf8
$mysqli->query("SET NAMES 'utf8'");
/*
* Это "официальный" объектно-ориентированный способ сделать это
* однако $connect_error не работал вплоть до версий PHP 5.2.9 и 5.3.0.
*/
if ($mysqli->connect_error) {
die('Ошибка подключения (' . $mysqli->connect_errno . ') '
. $mysqli->connect_error);
}
/*
* Если нужно быть уверенным в совместимости с версиями до 5.2.9,
* лучше использовать такой код
*/
if (mysqli_connect_error()) {
die('Ошибка подключения (' . mysqli_connect_errno() . ') '
. mysqli_connect_error());
}
//Получаем массив нашего меню из БД в виде массива
function getCat($mysqli){
$sql = 'SELECT * FROM `categories`';
$res = $mysqli->query($sql);
//Создаем масив где ключ массива является ID меню
$cat = array();
while($row = $res->fetch_assoc()){
$cat[$row['id']] = $row;
}
return $cat;
}
Далее нам нужно из этого массива построить дерево зависимости дочерних элементов от родительских проходя рекурсивно по всему массиву.
//Функция построения дерева из массива от Tommy Lacroix
function getTree($dataset) {
$tree = array();
foreach ($dataset as $id => &$node) {
//Если нет вложений
if (!$node['parent']){
$tree[$id] = &$node;
}else{
//Если есть потомки то перебераем массив
$dataset[$node['parent']]['childs'][$id] = &$node;
}
}
return $tree;
}
>
<?php
//Устанавливаем кодировку и вывод всех ошибок
header('Content-Type: text/html; charset=UTF-8');
error_reporting(E_ALL);
//Объектно-ориентированный стиль
$mysqli = new mysqli('localhost', 'user', 'pass', 'db');
//Устанавливаем кодировку utf8
$mysqli->query("SET NAMES 'utf8'");
/*
* Это "официальный" объектно-ориентированный способ сделать это
* однако $connect_error не работал вплоть до версий PHP 5.2.9 и 5.3.0.
*/
if ($mysqli->connect_error) {
die('Ошибка подключения (' . $mysqli->connect_errno . ') '
. $mysqli->connect_error);
}
/*
* Если нужно быть уверенным в совместимости с версиями до 5.2.9,
* лучше использовать такой код
*/
if (mysqli_connect_error()) {
die('Ошибка подключения (' . mysqli_connect_errno() . ') '
. mysqli_connect_error());
}
//Получаем массив нашего меню из БД в виде массива
function getCat($mysqli){
$sql = 'SELECT * FROM `categories`';
$res = $mysqli->query($sql);
//Создаем масив где ключ массива является ID меню
$cat = array();
while($row = $res->fetch_assoc()){
$cat[$row['id']] = $row;
}
return $cat;
}
//Функция построения дерева из массива от Tommy Lacroix
function getTree($dataset) {
$tree = array();
foreach ($dataset as $id => &$node) {
//Если нет вложений
if (!$node['parent']){
$tree[$id] = &$node;
}else{
//Если есть потомки то перебераем массив
$dataset[$node['parent']]['childs'][$id] = &$node;
}
}
return $tree;
}
//Получаем подготовленный массив с данными
$cat = getCat($mysqli);
//Создаем древовидное меню
$tree = getTree($cat);
//Шаблон для вывода меню в виде дерева
function tplMenu($category){
$menu = '<li>
<a href="#" title="'. $category['title'] .'">'.
$category['title'].'</a>';
if(isset($category['childs'])){
$menu .= '<ul>'. showCat($category['childs']) .'</ul>';
}
$menu .= '</li>';
return $menu;
}
/**
* Рекурсивно считываем наш шаблон
**/
function showCat($data){
$string = '';
foreach($data as $item){
$string .= tplMenu($item);
}
return $string;
}
//Получаем HTML разметку
$cat_menu = showCat($tree);
//Выводим на экран
echo '<ul>'. $cat_menu .'</ul>';
?>
Результат работы
Если Вы хотите использовать данное меню в админке своего сайта, то нужно переписать пару функций tplMenu() , showCat() .
<?php
function tplMenu($category,$str)
{
if($category['parent'] == 0){
$menu = '<option value="'.$category['id'].'">'.$category['title'].'</option>';
}else{
$menu = '<option value="'.$category['id'].'">'.$str.' '.$category['title'].'</option>';
}
if(isset($category['childs'])){
$i = 1;
for($j = 0; $j < $i; $j++){
$str .= '→';
}
$i++;
$menu .= showCat($category['childs'], $str);
}
return $menu;
}
/**
* Рекурсивно считываем наш шаблон
**/
function showCat($data, $str){
$string = '';
$str = $str;
foreach($data as $item){
$string .= tplMenu($item, $str);
}
return $string;
}
//Получаем HTML разметку
$cat_menu = showCat($tree, '');
//Выводим на экран
echo '<select><option value="0">Выбери '. $cat_menu .'</select>';
?>
В следующей статье мы научимся сортировать данное меню , до новых встреч.
21/09/2023 19:00:12
11/05/2022 23:31:37
12/05/2019 19:51:44
Доброго времени суток!
Попробуйте почитать здесь с примерами: https://www.php.net/manual/ru/language.references.pass.php
09/08/2021 22:56:26
18/03/2019 11:04:11
Попробуйте так поправить шаблон в скрипте.
<?php //Шаблон для вывода меню в виде дерева function tplMenu($category){ $menu = '<tr> <td><a href="#" title="'. $category['title'] .'">'. $category['title'].'</a></td>'; if(isset($category['childs'])){ $menu .= '<table>'. showCat($category['childs']) .'</table>'; } $menu .= '</tr>'; return $menu; } //Выводим на экран echo '<table>'. $cat_menu .'</table>'; ?>
При этом нужно понимать, что записи будут выводиться в одной ячейки, по этому используется вложенный список.
18/03/2019 12:09:11
21/09/2018 02:02:11
$items = [
0 => [
'id' => 1,
'parent' => 0,
'title' => '1'
],
1 => [
...
],
....
];
function recurseMenu(&$items = [], $parent = 0, &$nodeParent = []){
foreach ($items as $id => &$node) {
if($parent == 0){
if($node['parent'] == 0){
$this->recurseMenu($items, $id, $node);
}
}
else{
if($node['parent'] == $parent){
$nodeParent['child'][ $id ] = $node;
recurseMenu($items, $node['id'], $nodeParent['child'][ $id ]);
unset($items[$id]);
}
}
}
}
20/11/2017 01:11:09
Во-первых функция построения дерева не моя а Tommy Lacroix. И данная функция отлично работает. Если бы она выводила только два уровня, то я думаю читатели моего блога уже давно написали об этом. А так как жалоб нет и скрипт у меня прекрасно работает, то Ваше замечание тут не уместно. Скорей всего что-то Вы неправильно сделали...
20/11/2017 19:01:01
29/03/2017 06:40:31
Если я правильно понял, то вас интересуют "хлебные крошки" прочитайте эту статью Хлебные крошки многомерного меню PHP + MySQL
17/04/2017 16:57:51
28/03/2017 20:38:05
Иван, вам нужно использовать javascript + соответствующая верстка. Посмотрите в сторону фреймворка Bootstrap, там уже практически все готово.
28/03/2017 21:55:17