Сижу второй день и уже такого накостылил, что $&^#@%! Проблема в том, что не получается собрать дерево ресурсов дальше второго уровня.
Как я делаю... Получаю список всех документов из базы во временный одномерный массив следующего вида:
Код: Выделить всё
Array
(
[0] => Array
(
[id] => 1
[parent_id] =>
[title] => О луне
[uri] => about
)
[1] => Array
(
[id] => 2
[parent_id] =>
[title] => Услуги
[uri] => services
)
[2] => Array
(
[id] => 4
[parent_id] =>
[title] => Новости
[uri] => news
)
[3] => Array
(
[id] => 5
[parent_id] =>
[title] => Фотогалерея
[uri] => gallery
)
[4] => Array
(
[id] => 6
[parent_id] =>
[title] => Как добраться
[uri] => contacts
)
[5] => Array
(
[id] => 7
[parent_id] => 2
[title] => Боулинг
[uri] => services/bouling
)
[6] => Array
(
[id] => 8
[parent_id] => 2
[title] => Каток
[uri] => services/katok
)
и т.д.
)
Код: Выделить всё
[1] => Array
(
[title] => О луне
[uri] => about
)
Временный массив преобразую к следующему виду:
Код: Выделить всё
Array
(
[2] => Array
(
[children] => Array
(
[7] => Array
(
[id] => 7
[parent_id] => 2
[title] => Боулинг
[uri] => services/bouling
[children] => Array
(
[28] => Array
(
[id] => 28
[parent_id] => 7
[title] => Тарифы и акции
[uri] => services/bouling/tarify-i-akcii
)
[29] => Array
(
[id] => 29
[parent_id] => 7
[title] => Правила игры
[uri] => services/bouling/pravila-igry
)
[30] => Array
(
[id] => 30
[parent_id] => 7
[title] => Экскурсия в музей боулинга
[uri] => services/bouling/ekskursiya-v-muzej-boulinga
)
[31] => Array
(
[id] => 31
[parent_id] => 7
[title] => Спец меню
[uri] => services/bouling/spec-menyu
)
)
)
[8] => Array
(
[id] => 8
[parent_id] => 2
[title] => Каток
[uri] => services/katok
)
[9] => Array
(
[id] => 9
[parent_id] => 2
[title] => Детский клуб
[uri] => services/detskij-klub
)
[10] => Array
(
[id] => 10
[parent_id] => 2
[title] => Теннисный клуб
[uri] => services/tennisnyj-klub
)
[11] => Array
(
[id] => 11
[parent_id] => 2
[title] => Бильярд
[uri] => services/bilyard
)
[12] => Array
(
[id] => 12
[parent_id] => 2
[title] => Караоке
[uri] => services/karaoke
)
[13] => Array
(
[id] => 13
[parent_id] => 2
[title] => Квесты в реальности
[uri] => services/kvesty-v-realnosti
)
[14] => Array
(
[id] => 14
[parent_id] => 2
[title] => Кондитерская
[uri] => services/konditerskaya
)
[15] => Array
(
[id] => 15
[parent_id] => 2
[title] => Банкетный зал
[uri] => services/banketnyj-zal
)
[16] => Array
(
[id] => 16
[parent_id] => 2
[title] => Кафе
[uri] => services/kafe
)
[17] => Array
(
[id] => 17
[parent_id] => 2
[title] => Меню
[uri] => services/menu
)
[18] => Array
(
[id] => 18
[parent_id] => 2
[title] => Школа балета
[uri] => services/shkola-baleta
)
[19] => Array
(
[id] => 19
[parent_id] => 2
[title] => Аренда
[uri] => services/arenda
)
[20] => Array
(
[id] => 20
[parent_id] => 2
[title] => Luna. Disco. Nicht
[uri] => services/luna-disco-nicht
)
[21] => Array
(
[id] => 21
[parent_id] => 2
[title] => Детский лагерь
[uri] => services/detskij-lager
)
[22] => Array
(
[id] => 22
[parent_id] => 2
[title] => Корпоративные мероприятия
[uri] => services/korporativnye-meropriyatiya
)
)
)
[7] => Array
(
[children] => Array
(
[28] => Array
(
[id] => 28
[parent_id] => 7
[title] => Тарифы и акции
[uri] => services/bouling/tarify-i-akcii
)
[29] => Array
(
[id] => 29
[parent_id] => 7
[title] => Правила игры
[uri] => services/bouling/pravila-igry
)
[30] => Array
(
[id] => 30
[parent_id] => 7
[title] => Экскурсия в музей боулинга
[uri] => services/bouling/ekskursiya-v-muzej-boulinga
)
[31] => Array
(
[id] => 31
[parent_id] => 7
[title] => Спец меню
[uri] => services/bouling/spec-menyu
)
)
)
)
Максимум, что получилось это дойти до 3его уровня во временном массиве (и то очистить его от уже ненужных массивов не получается), но смержить его с итоговым массивом не получается.
Код формирующий массивы:
Код: Выделить всё
private function find_submenu_parent($array_for_search, $submenu_array, $submenu_parent_id) {
# пробегаем по всему массиву переданному параметром $array_for_search...
foreach ($array_for_search as $idx => $item) {
# ... если в текущем элементе массива $array_for_search есть элемент 'children', он является массивом и содержит ключ,
# равный переданному параметром $submenu_parent_id, id родителя подменю - сливаем массив $item['children'][$submenu_parent_id]
# с массивом переданным параметром $submenu_array
if (isset($item['children']) && is_array($item['children']) && array_key_exists($submenu_parent_id, $item['children'])) {
$array_for_search[$idx]['children'][$submenu_parent_id] = array_merge($item['children'][$submenu_parent_id], $submenu_array);
// return [1];
# ... если в текущем элементе массива $array_for_search есть элемент 'children', он является массивом, но не содержит ключ,
# равный переданному параметром $submenu_parent_id, id родителя подменю - вызываем $this->find_submenu_parent для массива 'children' текущего элемента
} else if (isset($item['children']) && is_array($item['children']) && !array_key_exists($submenu_parent_id, $item['children'])) {
$array_for_search[$idx]['children'] = $this->find_submenu_parent($item['children'], $submenu_array, $submenu_parent_id);
// return [2];
# ... иначе, если в текущем элементе массива $array_for_search не найден элемент 'children' - удаляем текущий элемент из массива $array_for_search
}/* else {
unset(
$array_for_search[$idx]
);
// return [3];
}
*/
# заносим в массив $iterated $idx перебранных элементов в массиве $array_for_search
// $iterated[] = $idx;
}
return $array_for_search;
}
public function run()
{
# получаем все документы сайта
$all_docs_tmp = Document::find()
->select([
'id',
'parent_id',
'title',
'uri'
])
->where([
'status' => 1,
'show_in_menu' => 1
])
->orderBy('parent_id ASC')
->asarray()
->all();
# реструктурируем массив со всеми документами сайта
$i = 1;
$merged = [];
foreach ($all_docs_tmp as $doc) {
$doc_parent_id = $doc['parent_id'] ?: 0;
# если у документа не указан родитель - заносим его в первый уровень массива $doc_tree? после чего убираем лишние поля id и parent_id ...
if ($doc_parent_id == 0) {
$doc_tree[$doc['id']] = $doc;
# удаляем лишние поля
unset(
$doc_tree[$doc['id']]['id'],
$doc_tree[$doc['id']]['parent_id']
);
# ... иначе создаём элемент 'children' в элементе с ключом, равным $doc_parent_id, в который заносим текущий документ, после чего удаляем
# лишние поля id и parent_id добавленного документа ...
} else {
$all_docs[$doc_parent_id]['children'][$doc['id']] = $doc;
# если в индексах первого уровня массива $doc_tree найден $doc_parent_id - сливаем массив $doc_tree[$doc_parent_id] с массивом $all_docs[$doc_parent_id] ...
if (array_key_exists($doc_parent_id, $doc_tree)/* && !in_array($doc_parent_id, $merged)*/) {
$doc_tree[$doc_parent_id] = array_merge($doc_tree[$doc_parent_id], $all_docs[$doc_parent_id]);
# удаляем обработанные элементы из массива $all_docs
/*
unset(
$all_docs[$doc_parent_id]
);
*/
if (!in_array($doc_parent_id, $merged)) {
$merged[] = $doc_parent_id;
/*
unset(
$all_docs[$doc_parent_id]
);
*/
}
# ... иначе ищем во всём массиве $all_docs документ с id равным $doc_parent_id (элемент с индексом $doc_parent_id) и сливаем с ним массив текущего документа
} else {
$all_docs = $this->find_submenu_parent($all_docs, $all_docs[$doc_parent_id], $doc_parent_id);
}
# удаляем лишние поля
/*
unset(
$all_docs[$doc_parent_id]['children'][$doc['id']]['id'],
$all_docs[$doc_parent_id]['children'][$doc['id']]['parent_id']
);
*/
}
}
return $this->render('@app/modules/menu/views/default/widgets/menu.php', [
'doc_tree' => $doc_tree,
'all_docs' => $all_docs,
'merged' => $merged,
'iterations' => ''
]);
# строим дерево
$i = 1; # - номер прохода по массиву $all_docs
$iterations = '';
while (count($all_docs) > 0 && $i <= 1) { # обходим массив $all_docs пока он не опустеет или пока количество проходов не достигнет 3
foreach ($all_docs as $idx => $doc) {
if ($doc['parent_id'] == NULL) { # если документ не имеет родителя...
$doc_tree[$doc['id']] = $doc;
# добавляем id документов у которых нет родителей в массив
$root_docs_ids[] = $doc['id'];
# удаление лишних полей и элементов массива $all_docs
unset(
$doc_tree[$doc['id']]['id'],
$doc_tree[$doc['id']]['parent_id'],
$all_docs[$idx]
);
} elseif (in_array($doc['parent_id'], $root_docs_ids)) { # если у документа есть родитель...
$doc_tree[$doc['parent_id']]['children'][$doc['id']] = $doc;
# удаление лишних полей и элементов массива $all_docs
unset(
$doc_tree[$doc['parent_id']]['children'][$doc['id']]['id'],
$doc_tree[$doc['parent_id']]['children'][$doc['id']]['parent_id'],
$all_docs[$idx]
);
} else {
$all_docs[$doc['id']] = $doc;
# удаление лишних полей и элементов массива $all_docs
unset(
$all_docs[$doc['id']]['id'],
$all_docs[$idx]
);
}
# удаляем обработанный документ из массива всех документов
// unset($all_docs[$idx]);
}
$iterations .= ($iterations != '') ? ', '.$i : $i;
$i++;
}
return $this->render('@app/modules/menu/views/default/widgets/menu.php', [
'doc_tree' => $doc_tree,
'all_docs' => $all_docs,
'iterations' => $iterations
]);
Наверняка есть способ проще, который я из-за отсутствия большого опыта не вижу.