Многоуровневое меню на PHP + MySQL

Многоуровневое меню на PHP + MySQL

Многоуровневое меню на PHP + MySQL

Ни один сайт не обходится без навигации или как еще называют "меню сайта". Так вот меню сайта бывает одноуровневым и многоуровневым в виде дерева. Если с одноуровневым меню особых сложностей в плане реализации не возникает, то при создании многоуровневого меню нужно хорошо подумать.

Самое главное в этой задаче это спроектировать базу данных для нашего многоуровневого меню. Создадим таблицу 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. А у категории Мотоциклы два потомка – это Кавасаки и Харлей. При этом у категории Лодки нет потомков. Надеюсь, что Вы поняли,как связать категории.

Далее переходим от слов к практике. Создадим таблицу Categories.


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());
}

Пишем функцию получения данных из таблицы Categories


//Получаем массив нашего меню из БД в виде массива
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;
}

Получаем массив вот такого вида, где ключ массива это ID категории.

Многоуровневое меню на PHP + MySQL

Далее нам нужно из этого массива построить дерево зависимости дочерних элементов от родительских проходя рекурсивно по всему массиву.

Функция построения дерева из массива от Tommy Lacroix


//Функция построения дерева из массива от 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 + MySQL

Скрипт целиком

>
<?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>';

?>

Результат работы

Многоуровневое меню на PHP + MySQL для админки

Если Вы хотите использовать данное меню в админке своего сайта, то нужно переписать пару функций 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>';
?>

Результат работы

 

В следующей статье мы научимся сортировать данное меню, до новых встреч.

Скачать: Многоуровневое меню на PHP + MySQL


Поддержи проект:


...
Владимир
Здравствуйте еще раз)  Проще прощения, странно пост разместился, много переводов строк.

19/04/2016 02:41:00

Администрация
Администрация

Реализовал Ваш функционал, пользуйтесь.

19/04/2016 10:02:11

...
Владимир
Здравствуйте! Благодарю Вас за такой отличный и понятный пример формирование дерева! Не могли бы Вы подсказать, как сделать, чтобы при каждом следующем уровне вложенности добавлялась еще одна стрелка? Я немного переделал функцию tplMenu, для формирования списка выбора, и хотелось бы, чтобы 2-й уровень вложенности обозначался 1-й стрелкой, 3-й уровень 2-я стрелками, 4-й уровень 3-я стрелками и т.д. Вот переделанная функция:

function tplMenu($category)
{   
   if($category['parent'] == 0)
   {
      $menu = "<option value='".$category['id']."'>".$category['title']."</option>";
   }
   else
   {   
      $menu = "<option value='".$category['id']."'>→ ".$category['title']."</option>";
   }
      if(isset($category['childs']))
      {
         $menu .= showCat($category['childs']);
      }
      
   $menu .= '';
   
   return $menu;
}
Пока получилось добавить стрелку только ко второму уровню вложенности. Благодарю Вас!

17/04/2016 16:39:08

Администрация
Администрация

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>';

19/04/2016 10:00:37

...
Николай
Спасибо за скрипт, никак не мог подобрать механизм, а здесь все просто и без воды.Пацаны - вообще ребята.

13/04/2016 09:20:21

Администрация
Администрация

Пожалуйста. Рад, что смог Вам помочь. 

13/04/2016 11:26:23

...
Иван
С удивительной легкостью этот скрипт адаптируется и для вывода древовидных комментариев. Внедрял в свою CMS, все получилось замечательно. Подобные варианты видел в сети, но у вас как-то все проще и понятней. Большое спасибо!

12/02/2016 01:36:06

Администрация
Администрация

Вам тоже спасибо за интерес к статье и отзыв.

12/02/2016 08:31:35

...
Vipvk
Спасибо большое это пожалуй самый толковый скрипт из всех что я искал для создания меню

01/02/2016 03:59:21

Администрация
Администрация

И Вам спасибо за отзыв.

01/02/2016 09:14:05


Copyright © 2014 - 2021 All rights reserved.