Современные сайты и интернет магазины требуют меню с неограниченной вложенностью. Обычно заказчики сами не знают, какая вложенность может понадобиться их сайту в будущем.
При создании сайтов и интернет магазинов многие программисты сталкиваются с проблемой вывода меню с неограниченной вложенностью. Ведь если сайт будет с меню без подкатегорий, то стоимость сайта будет очень низкая. Чтобы увеличить качество и стоимость создания сайта, в этой статье мы рассмотрим, как нужно делать меню неограниченной вложенностью, с 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, то это главная категория.
Вот дамп нашей базы данных:
-- -- База данных: `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
<?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
<?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]Спасибо за образец, ваш сайт помогает в освоении практики программирования.
Комментарий:
А можете сделать элементы не отступами, тегами
?
Заполните все поля
Написать комментарий