Javascript-форум (https://javascript.ru/forum/)
-   Серверные языки и технологии (https://javascript.ru/forum/server/)
-   -   трёхуровневое меню (https://javascript.ru/forum/server/71903-trjokhurovnevoe-menyu.html)

DivMan 21.12.2017 00:21

трёхуровневое меню
 
Надо у подкатегории вывести подкатегорию.

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

Такой код допускается на проекте? Какой способ ещё есть?

Делаю запрос

SELECT
    category.id AS catId, category.name AS catName,
    sub_category.id AS subCatId, sub_category.name AS subCatName,
    page.id AS pageId, page.name AS pageName

FROM category LEFT JOIN sub_category
ON sub_category.category_id = category.id LEFT JOIN page
ON page.sub_category_id = sub_category.id ORDER BY category.id


Мне присылается вот такой массив

$res = [
        ['catId' => 1, 'catName' => 'Программы', 'subCatId' => 1, 'subCatName' => "Антивирусы", 'pageId' => "1", 'pageName' => "Касперский"],
        ['catId' => 1, 'catName' => 'Программы', 'subCatId' => 4, 'subCatName' => "Аудио", 'pageId' => "4", 'pageName' => "VirtualDJ"],
        ['catId' => 1, 'catName' => 'Программы', 'subCatId' => 4, 'subCatName' => "Аудио", 'pageId' => "5", 'pageName' => "FL Studio"],
        ['catId' => 1, 'catName' => 'Программы', 'subCatId' => 1, 'subCatName' => "Антивирусы", 'pageId' => "6", 'pageName' => "NOD32"],
        ['catId' => 1, 'catName' => 'Программы', 'subCatId' => 2, 'subCatName' => "Запись", 'pageId' => "NULL", 'pageName' => "NULL"],
        ['catId' => 1, 'catName' => 'Программы', 'subCatId' => 3, 'subCatName' => "Интернет", 'pageId' => "NULL", 'pageName' => "NULL"],
        ['catId' => 2, 'catName' => 'Фильмы',    'subCatId' => 5, 'subCatName' => "Боевики", 'pageId' => "2", 'pageName' => "Джпеки Чан"],
        ['catId' => 2, 'catName' => 'Фильмы',    'subCatId' => 7, 'subCatName' => "Ужастики", 'pageId' => "3", 'pageName' => "Псы войны"],
        ['catId' => 2, 'catName' => 'Фильмы',    'subCatId' => 5, 'subCatName' => "Боевики", 'pageId' => "8", 'pageName' => "Американский ниндзя"],
        ['catId' => 2, 'catName' => 'Фильмы',    'subCatId' => 6, 'subCatName' => "Фантастика", 'pageId' => "NULL", 'pageName' => "NULL"],
    ];


Потом я из него делаю другой массив, который мне нужен. Вот так я его делаю

$mass = [];
foreach($res as $cat) {
    if (!array_key_exists($cat['catName'] . '|' . $cat['catId'], $mass)) {
        $mass[$cat['catName'] . '|' . $cat['catId']] = [$cat['subCatName'] . '|' . $cat['subCatId']=> [$cat['pageId']=>$cat['pageName']]];
    }

    else {
        $mass[$cat['catName']. '|' .$cat['catId']][$cat['subCatName'] . '|' .$cat['subCatId']][$cat['pageId']]=$cat['pageName'];
    }
}


После этого получился вот такой массив

Array
(
    [Программы|1] => Array
        (
            [Антивирусы|1] => Array
                (
                    [1] => Касперский
                    [6] => NOD32
                )

            [Аудио|4] => Array
                (
                    [4] => VirtualDJ
                    [5] => FL Studio
                )

            [Запись|2] => Array
                (
                    [] =>
                )

            [Интернет|3] => Array
                (
                    [] =>
                )

        )

    [Фильмы|2] => Array
        (
            [Боевики|5] => Array
                (
                    [2] => Джеки Чан
                    [8] => Американский ниндзя
                )

            [Ужастики|7] => Array
                (
                    [3] => Псы войны
                )

            [Фантастика|6] => Array
                (
                    [] =>
                )

        )

)


И потом уже, создаю списки

echo '<ul>';
foreach($mass as $key => $val) {
    $category = explode('|', $key);
    echo '<li><a href="/category/'.$category[1].'">'.$category[0].'</a>';
         foreach($val as $k => $v) {
            $subCategory = explode('|', $k);
                echo '<ul>';
                    echo '<li><a href="/sub-category/'.$subCategory[1].'">'.$subCategory[0].'</a>';
                         foreach($v as $postKey => $postVal) {
                            echo '<ul>';
                                echo '<li><a href="/post/'.$postKey.'">'.$postVal.'</a></li>';
                            echo '</ul>';
                         }
                    echo '</li>';
                echo '</ul>';
         }
    echo '</li>';
}
echo '</ul>';


Получается вот такое


laimas 21.12.2017 01:12

Запоминать уровни в переменных вне цикла когда текущий не равен им, сверяя каждый последующий строить список.

$mass[$cat['catName']. '|' .$cat['catId']][$cat['subCatName'] . '|' .$cat['subCatId']] - это никуда не годится, уж тогда построить человеческий промежуточный многомерный массив.

DivMan 21.12.2017 01:19

laimas,
По другому я не умею

laimas 21.12.2017 02:50

А $res ни о чем не говорит? )

У вас фиксированный уровень вложенности, причем каждое вложение, это отдельная таблица. Проще получить все раздельными запросами:

$level1 = SELECT * FROM category WHERE EXISTS (SELECT * FROM sub_category WHERE sub_category.category_id = category.id) ORDER BY id

$level2 = SELECT * FROM sub_category WHERE category_id IN (implode(',', array_column($level1, 'id'))) AND EXISTS (SELECT * FROM page WHERE page.sub_category_id = sub_category.id) ORDER BY sub_category_id

И из последней как и для второй по набору id из второй и непустых значений. Проходом в цикле первого уровня, получая данные из остальных уровней уровней построить список.

Это же самое можно сделать и с результатом одного запроса, если его правильно отсортировать на выходе.

Уже давно версии MySQL позволяют опускать AS, то есть просто category.id catId. И полезно давать таблицам алиас, чтобы не писать длинные портянки.

DivMan 21.12.2017 07:26

2 запроса это плохо

DivMan 21.12.2017 07:37

А о чём $res должна говорить?

laimas 21.12.2017 10:10

Цитата:

Сообщение от DivMan
2 запроса это плохо

Чем? И будет не два, а три.

Цитата:

Сообщение от DivMan
А о чём $res должна говорить?

О том что вывод из базы не подходит под разбор.

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

DivMan 21.12.2017 21:57

бред какой-то

laimas 22.12.2017 03:50

Цитата:

Сообщение от laimas
бред какой-то

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


Часовой пояс GMT +3, время: 16:20.