Вывод категорий и подкатегорий

Правильно ли я сделал вывод?

PHP:
  1. <?php
  2.  
  3. $host = ‘localhost’;
  4.     $db = ‘test’;
  5.     $user = ‘root’;
  6.     $pass = »;
  7.     $charset = ‘utf8’;
  8.     $dsn = «mysql:host=$host; dbname=$db;charset=$charset«;
  9.     $opt = [
  10.         PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
  11.         PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
  12.         PDO::ATTR_EMULATE_PREPARES   => false,
  13.         ];
  14.        
  15.     $pdo = new PDO($dsn, $user, $pass, $opt);
  16.    
  17.     $sql = «SELECT * FROM `category`»;
  18.    
  19.     $res = $pdo->query($sql)->fetchAll();
  20.    
  21.     echo ‘<ul>’;
  22.         foreach($res as $key => $val) {
  23.             $subCat = «SELECT * FROM sub_category WHERE category_id = « . $val[‘id’];
  24.             $result = $pdo->query($subCat)->fetchAll();
  25.            
  26.             echo ‘<li>’;
  27.                 echo ‘<a href=»cat-‘.$val[‘id’].‘»>’.$val[‘name’]. ‘</a>’;
  28.                
  29.                 echo ‘<ul>’;
  30.                 foreach($result as $k => $v) {
  31.                     echo ‘<li><a href=»sub-‘.$v[‘id’].‘»>’ . $v[‘name’] . ‘</a></li>’;
  32.                 }
  33.                 echo ‘</ul>’;
  34.             echo ‘</li>’;
  35.         }
  36.     echo ‘</ul>’;

Для каждой категории, сделал отельный запрос, на подкатегорию, это правильный подход?

Если сделать запрос на категории и подкатегории

Код (Text):
  1. SELECT category.id, category.name, sub_category.name
  2.     FROM category LEFT JOIN sub_category
  3.     ON sub_category.category_id = category.id

То получится вот такое

1 Программы Антивирусы
1 Программы Запись
1 Программы Интернет
1 Программы Аудио
2 Фильмы Боевики
2 Фильмы Фантастика
2 Фильмы Ужастики

И такой массив с массивами, будет сложнее вывести.

 

PDO::FETCH_GROUP группирует, но не выводит саму категорию

 

Я сделал, получилась такая штука

PHP:
  1. $host = ‘localhost’;
  2.     $db = ‘test’;
  3.     $user = ‘root’;
  4.     $pass = »;
  5.     $charset = ‘utf8’;
  6.     $dsn = «mysql:host=$host; dbname=$db;charset=$charset«;
  7.     $opt = [
  8.         PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
  9.         PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
  10.         PDO::ATTR_EMULATE_PREPARES   => false,
  11.         ];
  12.        
  13.     $pdo = new PDO($dsn, $user, $pass, $opt);
  14.    
  15.     $sql = «SELECT category.name, category.id as catId, sub_category.name, sub_category.id
  16.    FROM category LEFT JOIN sub_category
  17.    ON sub_category.category_id = category.id»;
  18.    
  19.     $res = $pdo->query($sql)->fetchAll(PDO::FETCH_GROUP);
  20.    
  21.     echo ‘<ul>’;
  22.     foreach($res as $key => $val) {
  23.         echo ‘<li>’;
  24.         echo ‘<a href=»/cat=».$val[0][«catId’].‘»>’.$key. ‘</a>’;
  25.         echo ‘<ul>’;
  26.             foreach($val as $k => $v) {
  27.                 echo ‘<li><a href=»sub-‘.$v[‘id’].‘»>’ . $v[‘name’] . ‘</a></li>’;
  28.             }
  29.         echo ‘</ul>’;
  30.         echo ‘</li>’;
  31.     }
  32.     echo ‘</ul>’;
 

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

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

Делаю запрос

Код (Text):
  1. SELECT
  2.     category.id AS catId, category.name AS catName,
  3.     sub_category.id AS subCatId, sub_category.name AS subCatName,
  4.     page.id AS pageId, page.name AS pageName
  5.    
  6. FROM category LEFT JOIN sub_category
  7. ON sub_category.category_id = category.id LEFT JOIN page
  8. ON page.sub_category_id = sub_category.id ORDER BY category.id

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

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

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

PHP:
  1. $mass = [];
  2. foreach($res as $cat) {
  3.     if (!array_key_exists($cat[‘catName’] . ‘|’ . $cat[‘catId’], $mass)) {
  4.         $mass[$cat[‘catName’] . ‘|’ . $cat[‘catId’]] = [$cat[‘subCatName’] . ‘|’ . $cat[‘subCatId’]=> [$cat[‘pageId’]=>$cat[‘pageName’]]];
  5.     }
  6.    
  7.     else {
  8.         $mass[$cat[‘catName’]. ‘|’ .$cat[‘catId’]][$cat[‘subCatName’] . ‘|’ .$cat[‘subCatId’]][$cat[‘pageId’]]=$cat[‘pageName’];
  9.     }
  10. }

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

Код (Text):
  1. Array
  2. (
  3.     [Программы|1] => Array
  4.         (
  5.             [Антивирусы|1] => Array
  6.                 (
  7.                     [1] => Касперский
  8.                     [6] => NOD32
  9.                 )
  10.  
  11.             [Аудио|4] => Array
  12.                 (
  13.                     [4] => VirtualDJ
  14.                     [5] => FL Studio
  15.                 )
  16.  
  17.             [Запись|2] => Array
  18.                 (
  19.                     [] =>
  20.                 )
  21.  
  22.             [Интернет|3] => Array
  23.                 (
  24.                     [] =>
  25.                 )
  26.  
  27.         )
  28.  
  29.     [Фильмы|2] => Array
  30.         (
  31.             [Боевики|5] => Array
  32.                 (
  33.                     [2] => Джеки Чан
  34.                     [8] => Американский ниндзя
  35.                 )
  36.  
  37.             [Ужастики|7] => Array
  38.                 (
  39.                     [3] => Псы войны
  40.                 )
  41.  
  42.             [Фантастика|6] => Array
  43.                 (
  44.                     [] =>
  45.                 )
  46.  
  47.         )
  48.  
  49. )

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

PHP:
  1. echo ‘<ul>’;
  2. foreach($mass as $key => $val) {
  3.     $category = explode(‘|’, $key);
  4.     echo ‘<li><a href=»/category/’.$category[1].‘»>’.$category[0].‘</a>’;
  5.          foreach($val as $k => $v) {
  6.             $subCategory = explode(‘|’, $k);
  7.                 echo ‘<ul>’;
  8.                     echo ‘<li><a href=»/sub-category/’.$subCategory[1].‘»>’.$subCategory[0].‘</a>’;
  9.                          foreach($v as $postKey => $postVal) {
  10.                             echo ‘<ul>’;
  11.                                 echo ‘<li><a href=»/post/’.$postKey.‘»>’.$postVal.‘</a></li>’;
  12.                             echo ‘</ul>’;
  13.                          }
  14.                     echo ‘</li>’;
  15.                 echo ‘</ul>’;
  16.          }
  17.     echo ‘</li>’;
  18. }
  19. echo ‘</ul>’;

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

 

Как-то странно у тебя данные хранятся. Зачем писать в каждой строке имя категории и имя подкатегории, если у них уже есть id? А если ты в последствии захочешь поменять название категории, ты будешь все строки в таблице менять?
На мой взгляд правильнее список категорий и подкатегорий хранить в отдельной таблице или массиве. Например так:

PHP:
  1. $category =
  2.     [
  3.         1 =>
  4.             [
  5.                 ‘name’ => ‘Программы’,
  6.                 ‘subcategory’ =>
  7.                     [
  8.                         1 => ‘Антивирусы’,
  9.                         2 => ‘Запись’,
  10.                         3 => ‘Аудио’,
  11.                     ]
  12.             ],
  13.         2 =>
  14.             [
  15.                 ‘name’ => ‘Фильмы’,
  16.                 ‘subcategory’ =>
  17.                     [
  18.                         1 => ‘Боевики’,
  19.                         2 => ‘Ужастики’,
  20.                         3 => ‘Фантастика’,
  21.                     ]
  22.             ],
  23.     ];
 

@Sergey_Tsarev Не получается сделать такой массив

А почему в твоём массиве, у подкатегорий одинаковые ключи? Как потом запрос составлять?

 

@Dimon2x, используй нормальные инструменты хранения деревьев в базе: Nested Sets, Materialized Paths и пр.

 

@Dimon2x, вполне. + существует куча готовых библиотек для работы с Nested Sets

 

Ну, а в чем проблема? Примерно такой запрос:

Код (Text):
  1. «SELECT `category` WHERE `catid` = ‘1’ AND `subcatid` = ‘2’»

Или можно получить все записи и на php их уже отсортировать так как нужно.
— Добавлено —
А одинаковые ключи в подкатегориях потому, что они никак между собой не пересекаются. Ведь они находятся в массиве конкретной категории. Например, если мне нужно вызвать название категории с id равным 1 я напишу так:

PHP:
  1. echo $category[1][‘name’];

А если хочу вызвать название подкатегории с id равным 2 из категории с id равным 1, то вот так:

PHP:
  1. echo $category[1][‘subcategory’][2];
 

Ну ты по статье разберись, почему оно работает, а код из проекта проект таскать. Ну можно свою библиотеку замутить, в принципе

Наверное, не знаю. Я не пользовался. По описанию ничего

 

@Sergey_Tsarev в БД у подкатегории Аудио id 4, а у тебя в массиве 3, ну и как потом сделать запрос, что вывелись все под категории а Аудио?
— Добавлено —

что-то я ни одной найти не могу

 

Ну я же тебе для примера написал :) Напиши массив, чтобы как у тебя все было. А ещё лучше создай в базе данных отдельную таблицу для категорий и подкатегорий.

 

@Sergey_Tsarev так у меня и есть 3 таблицы для этого

 

@Dimon2x, ну так и сделай тогда три простых запроса к базе:

1. Получить список всех категорий:

Код (Text):
  1. «SELECT * FROM ‘category'»

2. Получить список всех подкатегорий:

Код (Text):
  1. «SELECT * FROM ‘subcategory'»

3.Список программ, фильмов и т.п.

Код (Text):
  1. «SELECT * FROM ‘items'»

А дальше выводи на экран.

 

@Sergey_Tsarev создавать несколько запросов, когда можно только 1 это плохо

 

Зачем, если есть решения, как неограниченную глубину подкатегорий хранить в одной таблице?

 

Да я и не спорю :) Я это писал к тому, что вот так, на мой взгляд, лучше не делать:

PHP:
  1. $mass[$cat[‘catName’] . ‘|’ . $cat[‘catId’]] = [$cat[‘subCatName’] . ‘|’ . $cat[‘subCatId’]=> [$cat[‘pageId’]=>$cat[‘pageName’]]];
  2. $category = explode(‘|’, $key);

— Добавлено —

Лучше 3 простых запроса, чем один супернавороченный.
— Добавлено —
Да и данные полученные из первых двух запросов можно хранить в кэше или в сессии наример.

 

Кстати — а не быстрее для данной задачи — вначале выгрузить весь список категорий (целиком) и потом уже сдлеать обход полученного массива без запросов к базе?

 

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *