Как отобразить категорию и подкатегорию?

Как отобразить категорию и подкатегорию? У меня есть одна таблица в БД. Строка в этой таблице выглядит примерно так:

CREATE TABLE IF NOT EXISTS `category` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(45) NOT NULL, `parent_id` int(11) NOT NULL, `order` int(11) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM 

Я хочу показать категорию и подкатегорию, например, на этом сайте: http://www.dealsdirect.com.au/c/baby-1/ (меню слева)

Моя попытка:

 <?php include 'Category_model.php'; include 'Advert_model.php'; $nr = $_GET['id']; function show_category($nr){ try { $pdo = new PDO('mysql:host=localhost;dbname=advert', 'root', ''); $pdo -> setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $stmt = $pdo -> query("SELECT * FROM category where `parent_id` = $nr"); echo "<ul>"; foreach ($stmt as $row){ echo "<li><a href=category_view.php?id={$row['id']}> {$row['name']}</a>".show_category($row['id'])."</li>"; } echo "</ul>"; //$id = $_GET['id']; } catch(PDOException $e) { echo 'Error!: ' . $e->getMessage(); } } show_category($nr); 

Код ниже должен начать работу. Это «рекурсивная функция» – функция, которая вызывает себя. Как только что сказал Fake51, это не очень эффективно, но оно должно работать.

Вам понадобится CSS, чтобы структурировать список, который вы создали.

 function showItems($parent = 0) { $q = "SELECT id, name FROM category WHERE parent_id = $parent"; $q = mysql_query($q); if(mysql_num_rows($q)) { echo "<ul>"; while($r = mysql_fetch_row($q)) { echo "<li>"; echo "<a href=\"page.php?id=".$r[0]."\">".htmlentities($r[1])."</a>"; showItems($r[0]); echo "</li>"\n; } echo "</ul>\n"; } } showItems(); 

Изменить: поскольку до сих пор не было принято ответа, вот мой код изменен, чтобы сделать все это с помощью одного SQL-запроса, который должен быть намного более эффективным, хотя и немного более запутанным. Посмотрите, как это происходит для вас.

 //Recursive function to show menu items from a passed in array function showItems(&$menu, $parent = 0) { if(is_array($menu[$parent]) && sizeof($menu[$parent])) { echo "<ul>"; foreach($menu[$parent] as $num=>$name) { echo "<li>"; echo "<a href=\"page.php?id=".$num."\">".htmlentities($name)."</a>"; showItems($menu, $num); echo "</li>\n"; } echo "</ul>\n"; } } //Create a multi-dimensional array of ALL menu items, separated by parent $menu = array(); $q = "SELECT id, name, parent_id FROM category ORDER BY order"; $q = mysql_query($q); while($r = mysql_fetch_row($q)) { $menu[$r[2]][$r[0]] = $r[1]; } //Call the function showItems($menu); 

С такой структурой вам нужно сначала построить запрос для выбранного элемента, а затем построить запрос для выбранного родительского элемента. По сути, вам понадобится запрос для каждого уровня меню, который у вас есть, который должен быть видимым.

Именно по этой причине схема parent_id отношений дерева не очень эффективна. Гораздо лучше пойти с вложенным набором (http://en.wikipedia.org/wiki/Nested_set_model) или материализованным путем (http://en.wikipedia.org/wiki/Materialized_path). Если вы планируете некоторое обновление элементов, материализованный путь, вероятно, будет легче справиться в долгосрочной перспективе – я лично предпочитаю его, попробовав оба.

Поскольку вам нужна только категория и все ее подкатегории, вам не нужна рекурсия для построения меню, и вы, разумеется, не хотите рекурсии в своих вызовах БД. Таким образом, самое основное решение (весь код в одном файле) будет примерно таким:

 <?php include 'Category_model.php'; include 'Advert_model.php'; $pdo = new PDO('mysql:host=localhost;dbname=advert', 'root', ''); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $nr = $_GET['id']; $sql = 'SELECT * FROM category where `parent_id` = :id or `id` = :id'; $stmt = $pdo->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY)); $stmt->execute(array(':id' => $nr)); $menuCategories = $sth->fetchAll(); // If sub category id is passed fetch whole menu if ((1 == count($menuCategories)) && ($nr == $menuCategories[0]['id'])) { $nr = $menuCategories[0]['parent_id']; $stmt->execute(array(':id' => $nr)); $menuCategories = $sth->fetchAll(); } $parentCategoryFormat = '<h5><a href="category_view.php?id=%s">%s</a></h5>'; $subCategoryFormat = '<li><a href="category_view.php?id=%s">%s</a></li>'; $parentCategoryHTML = ''; $subMenuHTML = ''; foreach ($menuCategories as $row) { if ($row['id'] == $nr) { $parentCategoryHTML = sprintf($parentCategoryFormat, $row['id'], htmlentities($row['name'])); // Render parent category } else { $subMenuHTML .= sprintf($subCategoryFormat, $row['id'], htmlentities($row['name'])); // Render subcategory } } echo $parentCategoryHTML; if (!empty($subMenuHTML)) { echo "<ul>{$subMenuHTML}</ul>"; }