带子菜单的菜单

时间:2017-07-14 19:22:23

标签: php mysql

$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显示。

我该怎么做呢?

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);
}