php - 带有子菜单的菜单

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

数据库

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

结果

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 中的子类别 1 和子类别 2。

我怎样才能做到这一点?

最佳答案

考虑到您可能有少量的子类别级别(即:3 个,而不是数千个),最简单的解决方案可能是对每个“父级”执行查询,以获取其子级列表。
因为您使用的是准备好的语句,所以就生成查询计划而言,数据库引擎的负担将会减轻。

由于您线​​性输出菜单(即您没有将它们嵌套在 <ul> 之类的内部,因此我们要做的是构建一个包含每个菜单项的“输出”数组,但我们将向后构建它.我们将从您的 $chosencat 开始,并向上通过父级。之后,我们将反转数组并输出 HTML。请注意,这意味着即使您的 SQL 的 ORDER 也必须按降序排列。

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

关于php - 带有子菜单的菜单,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45110258/

相关文章:

PHP - 提交数据枚举组合按钮

mysql - 为什么 Parse.com 上的默认用户数据库称为 "_User"?

php - 将函数名称存储在数据库中然后执行

php - 如何从数据库中获取数据

mysql - POSTGRE 如何从分层表中选择父名称

php - 如何让PHP运行得更快?

php - Zend_Form_Element_Captcha 异常问题...?

php - MySQL/PHP : catch all entries between 2 times and check against 2 other times

php - 如何在mysql中搜索位于字符串中不同位置的不同单词

php - MySQL CONCAT : how to add data at the end of string and delete data at the beginning if size exceeded?