Современные сайты и интернет магазины требуют меню с неограниченной вложенностью. Обычно заказчики сами не знают, какая вложенность может понадобиться их сайту в будущем.
При создании сайтов и интернет магазинов многие программисты сталкиваются с проблемой вывода меню с неограниченной вложенностью. Ведь если сайт будет с меню без подкатегорий, то стоимость сайта будет очень низкая. Чтобы увеличить качество и стоимость создания сайта, в этой статье мы рассмотрим, как нужно делать меню неограниченной вложенностью, с 1-им циклом и 1-м запросом к базе, и какое меню делать не нужно. Начнем с того, как делать не нужно.
Как делать не нужно
Многие начинающие разработчики при создании меню, которое состоит, например, из 3 уровней вложенности, делают 3 вложенных цикла, в каждом цикле делают запросы к базе данных на выборку и вывод подкатегорий. В этом методе есть следующие недостатки:
- Огромное кол-во запросов к базе данных
Например, в интернет-магазине меню состоит из 300-т категорий и подкатегорий. Для вывода такого меню нужно 100-ни запросов, что очень сильно грузит сервер, и тормозит загрузку сайта. - Заказчик не сможет сам добавлять уровень вложенности из системы управления
- Если заказчик попросит добавить новый уровень вложенности, придется потратить очень много времени и сил на это.
У нас был заказчик, который очень удивлялся высокой стоимости поддержки сайта, т.к. у него и вывод меню был сделан не правильно, и все остальное. И для веб мастера нужно было потратить много сил и времени, чтобы что-то исправить на сайте. В итоге он решил сделать себе новый сайт. Хотя стоимость сайта была достаточно высока, но она окупилась через какое-то время, за счет низкой стоимости поддержки сайта.
Как делать нужно
Нужно делать так, чтобы вложенность меню генерировалась автоматически, и было всего 1-о обращение к базе данных.
Построение и вывод дерева на php
Сейчас мы сделаем вывод дерева на примере структуры сайта нашей компании (ox2.ru). Мы постоим дерево следующего вида (3 уровня вложенности):
Подготовка базы данных
Для построения дерева на php нам нужна база данных следующего вида:
Первое поле id категории, оно уникально для каждой категории. Второе поле name – имя категории, третье полеparent_id – оно ссылается на id категории родителя.
Например, для раздела Тариф «Оптимальный» parent_id = 4, поскольку она является подкатегорией раздела с id равным 4-ем (Создание интернет магазина, а она имеет parent_id равным 2-ум, т.к. является 2-ым уровнем вложенности раздела Услуги). Если parent_id = 0, то это главная категория.
Вот дамп нашей базы данных:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | -- -- База данных: `ox2.ru-test-base` -- CREATE DATABASE `ox2.ru-test-base` DEFAULT CHARACTER SET cp1251 COLLATE cp1251_general_ci; USE `ox2.ru-test-base`; -- -------------------------------------------------------- -- -- Структура таблицы `category` -- CREATE TABLE IF NOT EXISTS `category` ( `id` int (11) NOT NULL AUTO_INCREMENT, ` name ` varchar (255) DEFAULT NULL , `parent_id` int (11) NOT NULL DEFAULT '0' , PRIMARY KEY (`id`), KEY `parent_id` (`parent_id`) ) ENGINE=MyISAM DEFAULT CHARSET=cp1251 AUTO_INCREMENT=18 ; -- -- Дамп данных таблицы `category` -- INSERT INTO `category` (`id`, ` name `, `parent_id`) VALUES (1, 'Главная' , 0), (2, 'Услуги' , 0), (3, 'Наши работы' , 0), (4, 'Создание интернет магазина' , 2), (5, 'Создание сайта' , 2), (6, 'Продвижение сайта' , 2), (13, 'Продвижение по позициям' , 6), (7, 'Тариф «Оптимальный»' , 4), (8, 'Тариф «Расширенный»' , 4), (9, 'Тариф «Максимальный»' , 4), (10, 'Сайт визитка' , 5), (11, 'Фирменный сайт' , 5), (12, 'Корпоративный сайт' , 5), (14, 'Продвижение по трафику' , 6), (15, 'Сроки и гарантии' , 6), (16, 'Создание интернет магазина' , 3), (17, 'Создание сайта' , 3); |
Вывод дерева на PHP
Поскольку много читателей не знакомы с PHP5, мы сделали 2 версии вывода меню (на PHP4 и на PHP5)
Для тех кто программирует на PHP5, пропустите следующий раздел
Вывод меню на PHP4
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | <?php /** * PHP4 * Постоение дерева (меню неограниченной вложености) * @author дизайн студия ox2.ru */ mysql_connect( "localhost" , "root" ); //Подключаемся к базе данных mysql_select_db( "ox2.ru-test-base" ); //Выбираем базу данных /** * Метод читает из таблицы category все сточки, и * возвращает двумерный массив, в котором первый ключ - id родителя * категории (parent_id) * @return Array */ function getCategory() { $query = mysql_query( "SELECT * FROM `category`" ); $result = array (); while ( $row = mysql_fetch_array( $query )) { $result [ $row [ "parent_id" ]][] = $row ; } return $result ; } //В переменную $category_arr записываем все категории $category_arr = getCategory(); /** * Вывод дерева * @param Integer $parent_id - id-родителя * @param Integer $level - уровень вложености */ function outTree( $parent_id , $level ) { global $category_arr ; //Делаем переменную $category_arr видимой в функции if (isset( $category_arr [ $parent_id ])) { //Если категория с таким parent_id существует foreach ( $category_arr [ $parent_id ] as $value ) { //Обходим /** * Выводим категорию * $level * 25 - отступ, $level - хранит текущий уровень вложености (0,1,2..) */ echo "<div style='margin-left:" . ( $level * 25) . "px;'>" . $value [ "name" ] . "</div>" ; $level = $level + 1; //Увеличиваем уровень вложености //Рекурсивно вызываем эту же функцию, но с новым $parent_id и $level outTree( $value [ "id" ], $level ); $level = $level - 1; //Уменьшаем уровень вложености } } } outTree(0, 0); ?> |
Вывод меню на PHP5
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | <?php /** * PHP5 (ООП) * Постоение дерева (меню неограниченной вложености) * @author дизайн студия ox2.ru */ class TreeOX2 { private $_db = null; private $_category_arr = array (); public function __construct() { //Подключаемся к базе данных, и записываем подключение в переменную _db $this ->_db = new PDO( "mysql:dbname=ox2.ru-test-base;host=localhost" , "root" , "" ); //В переменную $_category_arr записываем все категории (см. ниже) $this ->_category_arr = $this ->_getCategory(); } /** * Метод читает из таблицы category все сточки, и * возвращает двумерный массив, в котором первый ключ - id - родителя * категории (parent_id) * @return Array */ private function _getCategory() { $query = $this ->_db->prepare( "SELECT * FROM `category`" ); //Готовим запрос $query ->execute(); //Выполняем запрос //Читаем все строчки и записываем в переменную $result $result = $query ->fetchAll(PDO::FETCH_OBJ); //Перелапачиваем массим (делаем из одномерного массива - двумерный, в котором //первый ключ - parent_id) $return = array (); foreach ( $result as $value ) { //Обходим массив $return [ $value ->parent_id][] = $value ; } return $return ; } /** * Вывод дерева * @param Integer $parent_id - id-родителя * @param Integer $level - уровень вложености */ public function outTree( $parent_id , $level ) { if (isset( $this ->_category_arr[ $parent_id ])) { //Если категория с таким parent_id существует foreach ( $this ->_category_arr[ $parent_id ] as $value ) { //Обходим ее /** * Выводим категорию * $level * 25 - отступ, $level - хранит текущий уровень вложености (0,1,2..) */ echo "<div style='margin-left:" . ( $level * 25) . "px;'>" . $value ->name . "</div>" ; $level ++; //Увеличиваем уровень вложености //Рекурсивно вызываем этот же метод, но с новым $parent_id и $level $this ->outTree( $value ->id, $level ); $level --; //Уменьшаем уровень вложености } } } } $tree = new TreeOX2(); $tree ->outTree(0, 0); //Выводим дерево ?> |
Комментарии (Написать комментарий)
Комментарий:
Если воспользоваться
Комментарий:
Сергей [14.08.2015]Большое спасибо!
Комментарий:
Иван [16.06.2015]Спасибо, ваша статья помогла мне решить поставленную задачу. Скрипт написал правда свой, но идею с логикой частично позаимствовал у вас )
Комментарий:
Александр [24.03.2015]Спасибо за образец, ваш сайт помогает в освоении практики программирования.
Комментарий:
А можете сделать элементы не отступами, тегами
?
Заполните все поля
Написать комментарий