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

151
20 декабря 2017, 23:08

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

<?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>';

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

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

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 Фильмы Ужастики

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

Answer 1

Писать надо определенно один запрос. А если не один, то использовать подготовленные запросы и передавать параметры туда как следует.

PDO в принципе и сам умеет группировать, хот такая группировка и не очень функциональна. Ваш код будет выглядеть примерно так (не проверено):

$st = $dbh->query("SELECT c.id, c.name
                         ,s.id as sub_id, s.name as sub_name
                   FROM category AS c
                   LEFT JOIN sub_category AS s ON (s.category_id = c.id)");
$categories = $st->fetchAll(PDO::FETCH_ASSOC | PDO::FETCH_GROUP);
echo '<ul>';
foreach($categories as $cId => $data) {
    echo '<li>';
    echo '<a href="cat-'.$cId.'">'.$data[0]['name']. '</a>';
    echo '<ul>';
    foreach($data as $sub) {
        echo '<li><a href="sub-'.$sub['sub_id'].'">' . $sub['sub_name'] . '</a></li>';
    }
    echo '</ul>';
    echo '</li>';
}
echo '</ul>';

Но и самому такую группировку сделать весьма просто:
исходные

$data = [
        ['id' => 1, 'name' => 'Программы', 'sub_id' => 1, 'sub_name' => "Антивирусы"],
        ['id' => 1, 'name' => 'Программы', 'sub_id' => 2, 'sub_name' => "Запись"],
        ['id' => 1, 'name' => 'Программы', 'sub_id' => 3, 'sub_name' => "Интернет"],
        ['id' => 1, 'name' => 'Программы', 'sub_id' => 4, 'sub_name' => "Аудио"],
        ['id' => 2, 'name' => 'Фильмы',    'sub_id' => 5, 'sub_name' => "Боевики"],
        ['id' => 2, 'name' => 'Фильмы',    'sub_id' => 6, 'sub_name' => "Фантастика"],
        ['id' => 2, 'name' => 'Фильмы',    'sub_id' => 7, 'sub_name' => "Ужастики"]
    ];

группировка

$result = [];
$cId = null;
foreach($data as $d){
    if($d['id'] != $cId) {
        $cId = $d['id'];
        $result[$cId] = ['id' => $d['id'], 'name' => $d['name'], 'sub' => [] ];
    }
    $result[$cId]['sub'][] = ['id' => $d['sub_id'], 'name' => $d['sub_name']];
}
print_r($result);
Answer 2

Почти всегда лучше делать один запрос. Только в запросе не забыть про сортировку

$pdo = new PDO($dsn, $user, $pass, $opt);
$sql = "SELECT
    category.id, category.name,
    sub_category.id sub_id, sub_category.name sub_name
  FROM category LEFT JOIN sub_category
  ON sub_category.category_id = category.id
  ORDER BY sub_category.category_id";
$res = $pdo->query($sql)->fetchAll();
echo '<ul>';
$old_id = null;
foreach($res as $key => $val) {
  if ($val['id'] !== $old_id) {
    if (isset($old_id))
      echo '</ul></li>';
    $old_id = $val['id'];
    echo '<li>';
    echo '<a href="cat-'.$val['id'].'">'.$val['name']. '</a>';
    echo '<ul>';
  }
  if (isset($val['sub_id']))
    echo '<li><a href="sub-'.$val['sub_id'].'">' . $val['sub_name'] . '</a></li>';
}
if (isset($old_id))
  echo '</ul></li>';
echo '</ul>';

Ну и на будущее: писать SELECT * плохо всегда. Даже если Вам нужно выбрать 50 полей. Всегда указывайте имена нужных Вам полей

READ ALSO
Сабмит формы без потери данных в инпуте

Сабмит формы без потери данных в инпуте

Дорогие друзья, вопрос будет звучать довольно странно , но всё же это нужно

210
Как быстро перенести проект с Laravel на Yii2? [требует правки]

Как быстро перенести проект с Laravel на Yii2? [требует правки]

Был разработан небольшой корпоративный портал на Laravel 54, но теперь требуется развернуть аналог на фреймворке Yii2, потому что он принят в команде,...

185
Добавление атрибутов в Magento. Ошибка с config.

Добавление атрибутов в Magento. Ошибка с config.

Добавляю группу атрибутов, папки и сами атибутыНо почему-то в бд не пишется новая инфа

154
Не приходят сообщения на почту с помощью функции mail php

Не приходят сообщения на почту с помощью функции mail php

В чем может быть проблема? mail возвращает true, то есть, он отправил сообщение (вроде как) почта моя вида post@yandexru, но никакого сообщения нет

151