$arrayCategories = array();
$stmt = $pdo->prepare("SELECT * FROM categories ORDER BY sort ASC");
$stmt->execute();
foreach($stmt as $item){
$arrayCategories[$item['id']] = array("parent_id" => $item['parent_id'], "name" => $item['name']);
}
buildMenu($arrayCategories, 0, 1);
function buildMenu($array, $parent, $level){
foreach ($array as $categoryId => $category){
if($parent == $category['parent_id']){
if($level == 1){
echo '<a href="/category/' . $categoryId . '">' . $category['name'] . ' (' . $categoryId . ')</a>';
echo '<br>';
}elseif($level == 2){
echo '<a href="/category/' . $categoryId . '">--' . $category['name'] . ' (' . $categoryId . ')</a>';
echo '<br>';
}elseif($level == 3){
echo '<a href="/category/' . $categoryId . '">----' . $category['name'] . ' (' . $categoryId . ')</a>';
echo '<br>';
}
$nextlevel = $level + 1;
buildMenu($array, $categoryId, $nextlevel);
}
}
}
DATABASE
id name parent_id sort
1 category 1 0 0
2 category 2 0 0
3 category 3 0 0
4 sub category 1 1 0
5 sub category 2 1 0
6 sub category 1 3 0
7 sub category 2 3 0
8 sub sub category 1 7 0
9 sub sub category 2 7 0
RESULT
category 1
--sub category 1
--sub category 2
category 2
category 3
--sub category 1
--sub category 2
----sub sub category 1
----sub sub category 2
我希望它只展开直到所选类别,而不是展开整个菜单
因此,如果我从类别3的子类别2中选择子子类别2,我不希望子类别1和子类别2从类别1显示。
我该怎么做呢?
答案 0 :(得分:0)
鉴于你可能有少量的子类别级别(即:3,而不是数千),最简单的解决方案可能是为每个&#34; parent&#34;执行查询,以获取其子列表。
因为您正在使用预准备语句,所以就生成查询计划而言,数据库引擎的负担会更少。
由于你线性输出了菜单(即你没有将它们嵌套在<ul>
以及诸如此类的东西中,我们要做的是构建一个包含#34;输出的数组,其中包含每个菜单项,但我们将向后构建它。我们将从你的$ selectedcat开始,然后通过父母向上工作。之后,我们将反转数组并输出HTML。这意味着即使你的SQL ORDER
必须处于desc顺序。
// Define the chosen category
$chosencat = 9;
// Prepare your SQL statement to find all the children of a particular parent_id
$categorySQL = $pdo->prepare("SELECT id, name, parent_id FROM categories WHERE parent_id=? ORDER BY sort DESC");
// Prepare your SQL statement to find the parent of the parent that is being iterated over
$parentSQL = $pdo->prepare("SELECT parent_id FROM categories WHERE id=?");
// Determine the parent of the chosen category, so that we can display all the children.
$parentSQL->execute(array($chosencat));
$currentParent = $parentSQL['parent_id'];
$lastParent = $chosencat;
// Loop through the categories
$arrayCategories = array();
$tempCategory = array();
do
{
// Get the children of the current parent
$categorySQL->execute(array($currentParent));
// Save all the children from the last iteration, to be applied to the child in this iteration
$lastChildren = $arrayCategories;
// Reset $arrayCategories (since we want to keep "one-level-up"ing)
$arrayCategories = array();
// Now add the children of the current parent to the newly "one-level-up'ed array"
foreach($categorySQL as $item)
{
// Build a list of the current category's children
$tempCategory = array("parent_id" => $item['parent_id'], "name" => $item['name'], "children" => array());
if ($item['id'] == $lastParent)
{$tempCategory["children"] = $lastChildren;}
// Apply it to the main $arrayCategories
$arrayCategories[] = $tempCategory;
}
// Now get the next parent to iterate over:
$lastParent = $currentParent;
$parentSQL->execute(array($currentParent));
$currentParent = $parentSQL['parent_id'];
}
while ($currentParent != 0); // Is there still a parent to iterate over?
// Now we can build a simple output array, based on the $arrayCategories just created
$menu_array = buildMenu($arrayCategories, 0);
// And output the menu
print implode("<br>\n", $menu_array);
// Function to build the menu
function buildMenu($array, $level)
{
$output = array();
foreach ($array as $categoryId => $category)
{
if (count($category['children']) > 0) // Does this have children?
{
// Prepend all the children before the parent.
// Note that we are merging the output of buildMenu before the current $output.
$output = array_merge(buildMenu($category['children'], ($level+1)), $output);
}
// The HTML for the menu item to output
$output[] = '<a href="/category/' . $categoryId . '">' . str_repeat("-", $level) . $category['name'] . ' (' . $categoryId . ')</a>';
}
// Now reverse the $output array.
// Currently $output has the top-most element listed last, but now we want it listed first.
return array_reverse($output);
}