Php 如何显示类别和子类别?
如何显示类别和子类别? 我有一张DB格式的桌子。此表中的行如下所示:Php 如何显示类别和子类别?,php,mysql,hierarchical-data,Php,Mysql,Hierarchical Data,如何显示类别和子类别? 我有一张DB格式的桌子。此表中的行如下所示: 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 <?p
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
<?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>";
}
我想在这个网站上显示类别和子类别:(左边的菜单)
我的尝试:
<?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);
对于这样的结构,您需要首先为所选项目构造一个查询,然后为所选项目父级构造一个查询。从本质上讲,您将需要对每一级菜单进行查询,这些菜单应该是可见的
这就是为什么树关系的父id方案不是很有效的原因。最好使用嵌套集(http://en.wikipedia.org/wiki/Nested_set_model)或物化路径(http://en.wikipedia.org/wiki/Materialized_path). 如果您希望对项目进行一些更新,那么从长远来看,物化路径可能更容易处理-我个人更喜欢它,已经尝试了这两种方法。下面的代码应该可以帮助您开始。这是一个“递归函数”——一个调用自身的函数。正如@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();
函数showItems($parent=0){
$q=“从父类中选择id、名称,其中父类\u id=$parent”;
$q=mysql\u查询($q);
if(mysql_num_行($q)){
回声“”;
而($r=mysql\u fetch\u row($q)){
回声“- ”;
回声“;
展示项目($r[0]);
回声“
”\n;
}
回声“
\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);
//递归函数,用于显示传入数组中的菜单项
函数showItems(&$menu,$parent=0){
if(is_数组($menu[$parent])&&sizeof($menu[$parent])){
回声“”;
foreach($menu[$parent]作为$num=>$name){
回声“- ”;
回声“;
showItems($menu$num);
回声“
\n”;
}
回声“
\n”;
}
}
//创建由父菜单项分隔的所有菜单项的多维数组
$menu=array();
$q=“从类别顺序中逐个顺序选择id、名称、父\u id”;
$q=mysql\u查询($q);
而($r=mysql\u fetch\u row($q)){
$menu[$r[2]][$r[0]]=$r[1];
}
//调用函数
展示项目(菜单);
因为您只需要显示类别及其所有子类别,所以构建菜单时不需要递归,当然也不希望在DB调用中使用递归。所以最基本的解决方案(所有代码都在一个文件中)是这样的:
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
<?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>";
}
我不知道该怎么办。请执行“算法”/“步骤如何”您首先需要使用mysql\u connect()
连接,然后使用mysql\u select\u db()选择一个数据库。如果您愿意,您应该能够将其转换为PDO。这太糟糕了。我更愿意做一个单一的选择,得到所有类别的数组,然后使用这个数组。此外,如果您可以将另一个字段添加到类别表“has_children”中并存储值(如yes/no或boolean),这将允许您使用更高效的算法。结果应在单个查询中获取,然后由构建菜单的递归函数处理。请同意重复查询是次优的。构建一组数组的单个查询将是一种更好的方法。某种形式的缓存也是一个明智的想法,因为它可能不太可能经常更改。我选择了这个,因为它很容易开始,也许应该建议这个改变。一点也不正确。您可以选择所有行,理想情况下按id对它们进行索引,然后遍历并生成结果。这是一种资源浪费,因为您不需要所有结果-可能隐藏了大量不需要详细信息的子类别项。除此之外,如果你有一个合适的结构,在php中遍历和构建结果将比在数据库中遍历和构建结果慢。当你点击一个子类别时,$nr将是子类别的id,因此只获取一行,而不是整个可见树。更不用说sql中的失败引用以及代码中的sql expoit向量了。@Fake51注意到了,谢谢。我更新了代码示例。我可能应该指出,即使更新后的代码也不是产品质量,我只是想用这段代码说明,在这种特定情况下,如果需要更复杂(更深)的菜单结构,就不需要递归,特别是使用DB查询的递归,更好的解决方案是更改“category”DB表结构,就像您在回答中建议的那样。