Уважаемые друзья, форма вопрос - ответ снова в строю!

Сортировка многоуровневого меню на PHP + MySQL

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

Если Вы не читали предыдущую часть статьи, то ознакомитесь с ней ( Многоуровневое меню на PHP + MySQL )

После того как вы создали многоуровневое меню, возникает резонный вопрос, как его отсортировать в нужном порядке? Первое что приходит в голову это создать в таблице с меню еще один столбец ( sort ) и в нем указывать номерную сортировку. Но так как у нас вся менюшка хранится в одной таблице и имеет родителей и потомков у которых номера сортировки могут совпадать, то сортировка простыми средствами MySQL становится не возможной. На помощь приходит PHP. Будем использовать функцию сравнения для сортировки массива, перед тем как создать из него дерево зависимостей. Тем самым получим отсортированное меню в том виде которое нам нужно.

Первое что нам нужно – добавить колонку в нашу таблицу с меню для сортировки и выставить нужные значения.

Модернизируем таблицу Categories.


--
-- Структура таблицы `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,
  `sort` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=20 ;

--
-- Дамп данных таблицы `categories`
--

INSERT INTO `categories` (`id`, `title`, `parent`, `sort`) VALUES
(1, 'Автомобили', 0, 1),
(2, 'Мотоциклы', 0, 2),
(3, 'Мазда', 1, 1),
(4, 'Хонда', 1, 2),
(5, 'Кавасаки', 2, 2),
(6, 'Харлей', 2, 1),
(7, 'Мазда 3', 3, 2),
(8, 'Мазда 6', 3, 1),
(9, 'Седан', 7, 2),
(10, 'Хечбэк', 7, 1),
(11, 'Лодки', 0, 3),
(12, 'Лифтбэк', 8, 2),
(13, 'Кроссовер', 8, 1),
(14, 'Белый', 13, 1),
(15, 'Красный', 13, 2),
(16, 'Черный', 13, 3),
(17, 'Зеленый', 13, 4),
(18, 'Мазда CX', 3, 3),
(19, 'Мазда MX', 3, 4);

Далее пишем функцию сравнения для сортировки массива.


//Функция сравнения для сортировки
function sortCat($a, $b){
    if ($a['sort'] == $b['sort']) {
        return 0;
    }
    return ($a['sort'] < $b['sort']) ? -1 : 1;
}

Вызываем функцию uasort вместе с нашей функцией сравнения передав в виде аргумента массив с меню.


//Функция построения дерева из массива от Tommy Lacroix
function getTree($dataset) {
	$tree = array();
	//Сортируем массив перед созданием из него дерева
	uasort($dataset, 'sortCat');

	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', '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();
	uasort($dataset, 'sortCat');

	foreach ($dataset as $id => &$node) {    
		//Если нет вложений
		if (!$node['parent']){
			$tree[$id] = &$node;
		}else{ 
			//Если есть потомки то перебераем массив
            $dataset[$node['parent']]['childs'][$id] = &$node;
		}
	}
	return $tree;
}

//Функция сравнения для сортировки
function sortCat($a, $b){
    if ($a['sort'] == $b['sort']) {
        return 0;
    }
    return ($a['sort'] < $b['sort']) ? -1 : 1;
}

//Получаем подготовленный массив с данными
$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>';

?>
Иван
21:41:29 27/03/2017г.
Здравствуйте. Спасибо за ваш сайт, очень понравился!  Скажите как можно сделать, что бы при клике на родительскую категорию открывался шаблон с категориями

Иван используйте http://getbootstrap.com/components/#nav-dropdowns или http://mm.onokumus.com/mm-vertical.html

- Администрация     - 14:09:04 28/03/2017г.

Alexey
09:11:27 19/12/2016г.
У меня есть вот такая структура (категории и подкатегории):

1

 1.1.

    1.1.1

     1.1.2

 1.2.

   1.2.1

    1.2.2

Необходимо отсортировать дочерние элементы и задать требуемый уровень вложенности для отображения на странице.

Например при уровне вложенности 1 получится такой вывод :

1

1.1

1.2

И так далее

Если задать уровень вложенности 2, то соответственно должны отображаться элементы 2 уровня вложенности

Алексей в принципе меню так и построено, вам нужно нужно выставить родителей в поле parent и указать сортировку данного меню. Как привязвать категории к подкатегориям смотрите в табличке http://bezramok-tlt.ru/?mode=2&post=21

- Администрация     - 13:37:55 02/02/2017г.

alexey
22:50:21 18/12/2016г.
Здравствуйте. Подскажите пожалуйста , какие изменения нужно внести в код, чтобы меню отображалось  с заданным уровнем вложенности  ?

Например необходимо вывести только дочерние элементы первого уровня.

Вы имеете ввиду вывод конкретной категории, ее подкатегорий как для интернет магазина? Киньте ссылку на пример того что Вы хотите.


 

- Администрация     - 08:34:22 19/12/2016г.

Alexey
09:14:25 12/11/2016г.
Здравствуйте. Очень полезная статья. Подскажите пожалуйста можно ли сделать из этого списка раскрывающийся  с добавлением  в вывод каких либо полей из базы?  

Например так :



Лодк и ссылка на описание

Автомобили ссылка на описание

При открытии дочерних элементов соответственно будут отображаться ссылки на описание дочерних элементов

Есть ли пример кода ?

Очень нужно. 

Создайте еще одну таблицу и записывайте в нее описание, таблицы свяжите по ID с меню. При клике по ссылке запросом достаете нужный контент из таблицы с описанием.

- Администрация     - 09:50:39 13/11/2016г.

Андрій
11:22:50 26/06/2016г.
Дуже дякую, Ви мені допомогли!! Довго ламав голову як це зробити!!! Ви геній!

Не за что. Сам долго голову ломал как это сделать, в итоге родилось решение этого вопроса.

- Администрация     - 14:16:36 26/06/2016г.

  • 1

Получить уведомление на Email

Введите код с картинки