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

22

Від автора: вітаю Вас, дорогий друже. Меню — це невід’ємна частина будь-якого сайту і навіть у тому випадку, якщо він складається всього лише з однієї сторінки. І так склалося, що, як правило, рідко зустрічаються меню одного рівня. Найбільше поширення отримали багаторівневі меню, так як вони дозволяють розташувати більшу кількість посилань на значно меншому просторі. Тому в даному уроці ми розглянемо формування деревоподібної структури даних для відображення на екран меню зазначеного типу.

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

Вже досить давно на нашому сайті було опубліковано урок з даної теми. І власне, рішення, яке представлене в уроці, дуже непогане і відмінно справляється з поставленим завданням, але в деяких випадках все ж не зовсім. Так як, по суті, структура даних, яка формується – не деревоподібна і підходить лише до тієї функції, яка показана і використовується для виводу посилань на екран.

Якщо ж буде потрібно передати дану структуру у визначене місце для подальшої обробки, то можуть виникнути певні проблеми. Тому цього відео я хотів би запропонувати дещо інше рішення щодо формування масиву даних і власне виведення його на екран.

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

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

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

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

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

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

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

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

Код наведених функцію, думаю, не потребує коментарів. Тепер ми можемо приступити до роботи і за великим рахунком ми з Вами напишемо рівно три функції і парочку шаблонів для відображення даних на екран. Отже, починаємо писати першу функцію, частина якої буде знайома тим, хто дивився вищевказаний урок:

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, ключами якого, є ідентифікатори батьківських категорій. І в кожній клітинці даного масиву, міститься додатковий подмассив – всіх категорій (дочірніх), у яких ідентифікатор батьківського категорії дорівнює ключа відповідного масиву.

В результаті при виклику даної функції і роздруківки на екран значення, що повертається, ми отримаємо наступний результат:

Деревоподібна структура для виведення багаторівневого меню на 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 , код якої наведено нижче:

Menu

$cats]); ?>

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

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

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

Ось власне і все. Всього Вам доброго і вдалого кодування!!!