Древовидная структура для вывода многоуровневого меню на php

Древовидная структура для вывода многоуровневого меню на php

От автора: приветствую Вас дорогой друг. Меню — это неотъемлемая часть любого сайта и даже в том случае, если он состоит всего лишь из одной страницы. И так сложилось, что, как правило, редко встречаются меню одного уровня. Наибольшее распространение получили как раз многоуровневые меню, так как они позволяют расположить большее количество ссылок на значительно меньшем пространстве. Поэтому в данном уроке мы рассмотрим формирование древовидной структуры данных для отображения на экран меню указанного типа.

скачать исходники

Уже достаточно давно на нашем сайте был опубликован урок по данной теме. И собственно, решение, которое представлено в уроке, очень неплохое и отлично справляется с поставленной задачей, но в некоторых случаях все же не совершенно. Так как, по сути, структура данных, которая формируется – не древовидная и подходит лишь к той функции, которая показана и используется для вывода ссылок на экран.

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

Фреймворк YII2. Быстрая разработка с современным PHP фреймворком

Узнай тонкости современной веб-разработки с помощью фреймворка YII2

Узнать подробнее

Для начала, хотел бы немного остановиться на заготовке того скрипта с которым мы будем работать. Собственно он состоит всего лишь из двух файлов – index.php и functions.php.

Код файла index.php:

<?php
require "functions.php";
$mysqli = db_connect('localhost', 'root', '', 'tree_menu');
$cats = getCategories($mysqli);

Как Вы видите все предельно просто – подключаем файл functions.php, в котором определены и будут сегодня определяться функции. Далее вызываем функцию подключения к базе данных и после этого вызываем на исполнение функцию getCategories(), которая вернет в виде массива выборку информации из таблицы базы данных, с которой мы будем сегодня работать, в вот таком виде:

Древовидная структура для вывода многоуровневого меню на php

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

Древовидная структура для вывода многоуровневого меню на php

Напомню, что в поле title содержится заголовок категории или ссылки меню, в поле parent_id – идентификатор родительской категории, причем элементы самого верхнего уровня в данном поле содержат 0 и наконец, поле id – это идентификатор таблицы.

Далее, код файла functions.php:

<?php
function db_connect($host, $user, $password, $db_name) {
 $link = mysqli_connect($host, $user, $password, $db_name);
 if (!$link) {
 die('Ошибка подключения (' . mysqli_connect_errno() . ') '
 . mysqli_connect_error());
 }
 return $link;
}

function getCategories($link) {
 if ($result = mysqli_query($link, "SELECT * FROM categories")) {
 return mysqli_fetch_all($result, MYSQLI_ASSOC);
 }
}

Код приведенных функцию, думаю, не нуждается в комментариях. Теперь мы можем приступить к работе и по большому счету мы с Вами напишем ровно три функции и парочку шаблонов для отображения данных на экран. Итак, начинаем писать первую функцию, часть которой будет знакома тем, кто смотрел вышеуказанный урок:

function createTree($arr) {
 $parents_arr = array();
 foreach($arr as $key=>$item) {
  $parents_arr[$item['parent_id']][$item['id']] = $item;
 }
return $parents_arr;
}

Хотел бы заметить, что код еще не завершен – это только начало. Обратите внимание, что в качестве аргумента мы будем передавать массив из которого будет сформирована древовидная структура. Как Вы видите в коде, используя цикл foreach, мы обходим массив, переданный в виде аргумента, и формируем новый — $parents_arr, ключами которого, являются идентификаторы родительских категорий. И в каждой ячейке данного массива, содержится дополнительный подмассив – всех категорий (дочерних), у которых идентификатор родительской категории равен ключу соответствующего массива.

В итоге при вызове данной функции и распечатки на экран возвращаемого значения, мы получим следующий результат:

Фреймворк YII2. Быстрая разработка с современным PHP фреймворком

Узнай тонкости современной веб-разработки с помощью фреймворка YII2

Узнать подробнее

Древовидная структура для вывода многоуровневого меню на php

Теперь, мы подготовили данные и наша задача, состоит в том, что бы сформировать такой многоуровневый массив, в котором на первом уровне вложенности присутствовали только родительские элементы высшего уровня, далее в каждом из них будет определен элемент children, в котором будет содержаться массив дочерних элементов. Которые в свою очередь, если содержат потомков, так же будут их хранить в указанном элементе. Таким образом, нам нужно получить массив вот такого вида:

Древовидная структура для вывода многоуровневого меню на php

А значит, мы можем продолжить писать код функции и несколько изменим возвращаемое значение:

function createTree($arr) {
 $parents_arr = array();
 foreach($arr as $key=>$item) {
  $parents_arr[$item['parent_id']][$item['id']] = $item;
 }
 $treeElem = $parents_arr[0];
 generateElemTree($treeElem,$parents_arr);
 
 return $treeElem;
} 

Обратите внимание, что мы создаем новый массив $treeElem, который далее возвращается как результат работы функции. И по умолчанию сохраняем в него элементы самого высокого уровня, которые содержатся в ключе с индексом 0, массива $parents_arr. По сути, сейчас мы получили массив элементов верхнего уровня, в который нужно добавить дочерние элементы, непосредственно в ячейку с ключом children. И сделает это дополнительная функция generateElemTree(), которую мы сейчас с Вами напишем.

Итак, код функции generateElemTree():

function generateElemTree(&$treeElem,$parents_arr) {
 foreach($treeElem as $key=>$item) {
  if(!isset($item['children'])) {
 $treeElem[$key]['children'] = array();
  }
  if(array_key_exists($key,$parents_arr)) {
 $treeElem[$key]['children'] = $parents_arr[$key];
 generateElemTree($treeElem[$key]['children'],$parents_arr);
  }
 }
}

Важно! Первый аргумент функции – это ссылка на массив $treeElem , так как нам нужно его изменить – доработать и вернуть как результат работы функции createTree(). Второй же аргумент это массив который мы с Вами получили в выше указанной функции. Собственно работа функции хоть и кажется сложной, но на самом деле очень проста.

Для начала, проверяем есть ли в переданном массиве элемент с ключем ‘children’ и если его нет то мы его создаем и инициализируем пустым массивом:

if(!isset($item['children'])) {
 $treeElem[$key]['children'] = array();
} 

А далее мы проверим, есть ли в массиве $parents_arr, элемент с ключом $key. При этом, напомню что в $key – содержится идентификатор текущего элемента, а в массиве $parents_arr, ключи это идентификаторы родительских элементов. Соответственно если условие выполнилось, значит, мы нашли дочерние элементы для текущего элемента. Соответственно массив дочерних элементов записываем я ячейку с ключом children. Затем рекурсивно вызываем эту же функцию, передавая при этом как раз найденный массив дочерних элементов, ведь они так же в свою очередь могут быть родителями для других элементов.

Вот собственно и все, если распечатать на экран содержимое массива $treeElem, мы получим желаемую древовидную структуру данных, которая показана на рисунке выше. Теперь необходимо вывести на экран полученные данные. Для этого напишем функцию шаблонизатор:

function renderTemplate($path,$arr) {
 $output = '';
 if(file_exists($path)) {
  extract($arr);
  ob_start();
  include $path;
  $output = ob_get_clean();
 }
 return $output;
} 

Код данной функции я позаимствовал из урока по созданию собственного шаблонизатора, а значит, комментировать ее я не буду, так как в уроке приведено подробнейшее описание.

Теперь, думаю, стоит привести код файла index.php, так как именно в нем мы будем использовать только что написанную функцию:

require "functions.php";
$mysqli = db_connect('localhost', 'root', '', 'tree_menu');
$cats = getCategories($mysqli);
$cats = createTree($cats);
echo renderTemplate('template.php',['cats'=>$cats]);

Как Вы видите, с помощью шаблонизатора, подключается файл template.php , код которого приведен ниже:

<h2>Menu</h2>
<?php if(isset($cats)) : ?>
 <?php echo renderTemplate('menu_part.php',['cats'=>$cats]); ?>
<?php endif; ?>

Внутри шаблоны мы опять же обращаемся к функции шаблонизатора и подгружаем дополнительный шаблон в который передается все та же переменная cats. Хотел бы отметить что так как мы не знаем сколько уровней вложенности в нашей древовидной структуре, соответственно нам нужно рекурсивно обрабатывать ее, а значит рекурсивно подгружать шаблон который будет выводить один уровень вложенности, что собственно и реализовано, используя дополнительный шаблон, код которого приведен ниже:

<ul style="margin-left:10px;">
 
 <?php foreach($cats as $cat) : ?>
  <li><a href="/category/<?php echo $cat['id']; ?>"><?php echo $cat['title']; ?></a></li>
  <?php if(count($cat['children']) > 0) : ?>
 <?php echo renderTemplate('menu_part.php',['cats'=>$cat['children']]); ?>
  <?php  endif; ?>
 
 <?php endforeach; ?>

</ul>

Логика работы шаблона сводится к следующему: используя цикл foreach() обходим элементы одного уровня и если у элемента в ячейке ‘children’, содержится массив дочерних элементов – рекурсивно, вызываем функцию renderTemplate(), подгружаем этот же шаблон, но при этом передаем в качестве переменной ‘cats’ ,массив дочерних элементов. При этом на экране, в качестве результата мы увидим следующее:

Древовидная структура для вывода многоуровневого меню на php

Вот собственно и все. Всего Вам доброго и удачного кодирования!!!

Фреймворк YII2. Быстрая разработка с современным PHP фреймворком

Узнай тонкости современной веб-разработки с помощью фреймворка YII2

Узнать подробнее
Самые свежие новости IT и веб-разработки на нашем Telegram-канале

Курс по программированию на языке PHP

Изучите PHP с нуля до результата!

Смотреть курс

Метки:

Похожие статьи:

Комментарии Вконтакте:

Комментарии Facebook:

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Я не робот.

Spam Protection by WP-SpamFree