Від автора: вітаю Вас, дорогий друже. Меню — це невід’ємна частина будь-якого сайту і навіть у тому випадку, якщо він складається всього лише з однієї сторінки. І так склалося, що, як правило, рідко зустрічаються меню одного рівня. Найбільше поширення отримали багаторівневі меню, так як вони дозволяють розташувати більшу кількість посилань на значно меншому просторі. Тому в даному уроці ми розглянемо формування деревоподібної структури даних для відображення на екран меню зазначеного типу.
Вже досить давно на нашому сайті було опубліковано урок з даної теми. І власне, рішення, яке представлене в уроці, дуже непогане і відмінно справляється з поставленим завданням, але в деяких випадках все ж не зовсім. Так як, по суті, структура даних, яка формується – не деревоподібна і підходить лише до тієї функції, яка показана і використовується для виводу посилань на екран.
Якщо ж буде потрібно передати дану структуру у визначене місце для подальшої обробки, то можуть виникнути певні проблеми. Тому цього відео я хотів би запропонувати дещо інше рішення щодо формування масиву даних і власне виведення його на екран.
Для початку, хотів би трохи зупинитися на заготівлі того скрипта з яким ми будемо працювати. Власне він складається всього лише з двох файлів – index.php і functions.php.
Код файлу index.php:
Як Ви бачите все гранично просто – підключаємо файл functions.php, в якому визначені і будуть сьогодні визначатися функції. Далі викликаємо функцію підключення до бази даних і після цього викликаємо на виконання функцію getCategories(), яка поверне у вигляді масиву вибірку інформації з таблиці бази даних, з якою ми будемо сьогодні працювати, ось в такому вигляді:
Для даного уроку я використовую ту ж базу даних, що і в зазначеному вище відео.
Нагадаю, що в полі 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, ключами якого, є ідентифікатори батьківських категорій. І в кожній клітинці даного масиву, міститься додатковий подмассив – всіх категорій (дочірніх), у яких ідентифікатор батьківського категорії дорівнює ключа відповідного масиву.
В результаті при виклику даної функції і роздруківки на екран значення, що повертається, ми отримаємо наступний результат:
Тепер, ми підготували дані і наше завдання полягає в тому, що б сформувати такий багаторівневий масив, в якому на першому рівні вкладеності були присутні тільки батьківські елементи вищого рівня, далі в кожному з них буде визначений елемент children, в якому буде міститися масив дочірніх елементів. Які в свою чергу містять нащадків, так само будуть їх зберігати в зазначеному елементі. Таким чином, нам потрібно отримати масив ось такого вигляду:
А значить, ми можемо продовжити писати код функції і трохи змінимо значення, що повертається:
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’ ,масив дочірніх елементів. При цьому на екрані, як результат ми побачимо наступне:
Ось власне і все. Всього Вам доброго і вдалого кодування!!!