Правильно ли я сделал вывод? PHP: <?php $host = 'localhost'; $db = 'test'; $user = 'root'; $pass = ''; $charset = 'utf8'; $dsn = "mysql:host=$host; dbname=$db;charset=$charset"; $opt = [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_EMULATE_PREPARES => false, ]; $pdo = new PDO($dsn, $user, $pass, $opt); $sql = "SELECT * FROM `category`"; $res = $pdo->query($sql)->fetchAll(); echo '<ul>'; foreach($res as $key => $val) { $subCat = "SELECT * FROM sub_category WHERE category_id = " . $val['id']; $result = $pdo->query($subCat)->fetchAll(); echo '<li>'; echo '<a href="cat-'.$val['id'].'">'.$val['name']. '</a>'; echo '<ul>'; foreach($result as $k => $v) { echo '<li><a href="sub-'.$v['id'].'">' . $v['name'] . '</a></li>'; } echo '</ul>'; echo '</li>'; } echo '</ul>'; Для каждой категории, сделал отельный запрос, на подкатегорию, это правильный подход? Если сделать запрос на категории и подкатегории Код (Text): SELECT category.id, category.name, sub_category.name FROM category LEFT JOIN sub_category ON sub_category.category_id = category.id То получится вот такое 1 Программы Антивирусы 1 Программы Запись 1 Программы Интернет 1 Программы Аудио 2 Фильмы Боевики 2 Фильмы Фантастика 2 Фильмы Ужастики И такой массив с массивами, будет сложнее вывести.
Я сделал, получилась такая штука PHP: $host = 'localhost'; $db = 'test'; $user = 'root'; $pass = ''; $charset = 'utf8'; $dsn = "mysql:host=$host; dbname=$db;charset=$charset"; $opt = [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_EMULATE_PREPARES => false, ]; $pdo = new PDO($dsn, $user, $pass, $opt); $sql = "SELECT category.name, category.id as catId, sub_category.name, sub_category.id FROM category LEFT JOIN sub_category ON sub_category.category_id = category.id"; $res = $pdo->query($sql)->fetchAll(PDO::FETCH_GROUP); echo '<ul>'; foreach($res as $key => $val) { echo '<li>'; echo '<a href="/cat='.$val[0]['catId'].'">'.$key. '</a>'; echo '<ul>'; foreach($val as $k => $v) { echo '<li><a href="sub-'.$v['id'].'">' . $v['name'] . '</a></li>'; } echo '</ul>'; echo '</li>'; } echo '</ul>';
Я усложнил задачу, теперь надо у подкатегории вывести подкатегорию. Убил 2 дня, перепробовал всякие способы, в итоге сделал свой велосипед на костылях, рекурсией мне такое задание сделать очень сложно. Такой код допускается на проекте? Какой способ ещё есть? Делаю запрос Код (Text): 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 Мне присылается вот такой массив PHP: $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"], ]; Потом я из него делаю другой массив, который мне нужен. Вот так я его делаю PHP: $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']; } } После этого получился вот такой массив Код (Text): 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 ( [] => ) ) ) И потом уже, создаю списки PHP: 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>'; Получается вот такое
Как-то странно у тебя данные хранятся. Зачем писать в каждой строке имя категории и имя подкатегории, если у них уже есть id? А если ты в последствии захочешь поменять название категории, ты будешь все строки в таблице менять? На мой взгляд правильнее список категорий и подкатегорий хранить в отдельной таблице или массиве. Например так: PHP: $category = [ 1 => [ 'name' => 'Программы', 'subcategory' => [ 1 => 'Антивирусы', 2 => 'Запись', 3 => 'Аудио', ] ], 2 => [ 'name' => 'Фильмы', 'subcategory' => [ 1 => 'Боевики', 2 => 'Ужастики', 3 => 'Фантастика', ] ], ];
@Sergey_Tsarev Не получается сделать такой массив А почему в твоём массиве, у подкатегорий одинаковые ключи? Как потом запрос составлять?
@Dimon2x, используй нормальные инструменты хранения деревьев в базе: Nested Sets, Materialized Paths и пр.
@mkramer применять сразу готовые решения, это наверно плохо, потому что так ничему не научусь --- Добавлено --- @mkramer эта библиотека нормальная? http://www.sesmikcms.ru/pages/read/...derevjami-nested-sets/?lang=ru&name=site_view
Ну, а в чем проблема? Примерно такой запрос: Код (Text): "SELECT `category` WHERE `catid` = '1' AND `subcatid` = '2'" Или можно получить все записи и на php их уже отсортировать так как нужно. --- Добавлено --- А одинаковые ключи в подкатегориях потому, что они никак между собой не пересекаются. Ведь они находятся в массиве конкретной категории. Например, если мне нужно вызвать название категории с id равным 1 я напишу так: PHP: echo $category[1]['name']; А если хочу вызвать название подкатегории с id равным 2 из категории с id равным 1, то вот так: PHP: echo $category[1]['subcategory'][2];
Ну ты по статье разберись, почему оно работает, а код из проекта проект таскать. Ну можно свою библиотеку замутить, в принципе Наверное, не знаю. Я не пользовался. По описанию ничего
@Sergey_Tsarev в БД у подкатегории Аудио id 4, а у тебя в массиве 3, ну и как потом сделать запрос, что вывелись все под категории а Аудио? --- Добавлено --- что-то я ни одной найти не могу
Ну я же тебе для примера написал Напиши массив, чтобы как у тебя все было. А ещё лучше создай в базе данных отдельную таблицу для категорий и подкатегорий.
@Dimon2x, ну так и сделай тогда три простых запроса к базе: 1. Получить список всех категорий: Код (Text): "SELECT * FROM 'category'" 2. Получить список всех подкатегорий: Код (Text): "SELECT * FROM 'subcategory'" 3.Список программ, фильмов и т.п. Код (Text): "SELECT * FROM 'items'" А дальше выводи на экран.
Да я и не спорю Я это писал к тому, что вот так, на мой взгляд, лучше не делать: PHP: $mass[$cat['catName'] . '|' . $cat['catId']] = [$cat['subCatName'] . '|' . $cat['subCatId']=> [$cat['pageId']=>$cat['pageName']]]; $category = explode('|', $key); --- Добавлено --- Лучше 3 простых запроса, чем один супернавороченный. --- Добавлено --- Да и данные полученные из первых двух запросов можно хранить в кэше или в сессии наример.
Кстати - а не быстрее для данной задачи - вначале выгрузить весь список категорий (целиком) и потом уже сдлеать обход полученного массива без запросов к базе?
Хорошая статья! Только я вот не понял по какому принципу добавляются данные в данную структуру. Там очень замороченно написанно в разделе где обновление данных.
Ну так, Nested Sets хороши при выборке, а добавление данных да - весьма заморочное. Вот, я попытался стрелками показать путь формирования left и right у Nested Sets
Случайно нашёл способ вывода дерева Adjacency, это хороший код? PHP: function get_tree($tree, $pid) { $html = ''; foreach ($tree as $row) { if ($row['pid'] == $pid) { $html .= '<li>' . "\n"; $html .= ' ' . $row['name'] . "\n"; $html .= ' ' . get_tree($tree, $row['id']); $html .= '</li>' . "\n"; } } return $html ? '<ul>' . $html . '</ul>' . "\n" : ''; } $tree = array( array('name' => 'Уровень 1', 'id' => 1, 'pid' => 0), array('name' => 'Уровень 1.1', 'id' => 2, 'pid' => 1), array('name' => 'Уровень 1.2', 'id' => 3, 'pid' => 1), array('name' => 'Уровень 1.3', 'id' => 4, 'pid' => 1), array('name' => 'Уровень 2', 'id' => 5, 'pid' => 0), array('name' => 'Уровень 2.1', 'id' => 6, 'pid' => 5), array('name' => 'Уровень 2.2', 'id' => 7, 'pid' => 5), array('name' => 'Уровень 3', 'id' => 8, 'pid' => 0), array('name' => 'Уровень 3.1', 'id' => 9, 'pid' => 8), array('name' => 'Уровень 3.1.1', 'id' => 10, 'pid' => 9), array('name' => 'Уровень 3.1.2', 'id' => 11, 'pid' => 9), ); echo get_tree($tree, 0);