带有MPTTA层次结构的简单PHP菜单

带有MPTTA层次结构的简单PHP菜单,php,mysql,menu,Php,Mysql,Menu,我正在尝试使用PHP创建一个简单的无序列表菜单。该列表是从MySQL填充的。我很难找到符合我具体需要的说明 要求 我试图避免使用自引用函数。 我试图通过一个性能效率查询来实现这一点。 我正在使用一种改进的预排序树遍历算法来显示菜单。 每行必须由列表项标记包围。 必须在节点开始和结束的位置打开和关闭列表 代码: PHP部分 $topmenu = ''; $nodes=array(); $nlbr = "\n"; // Now, retrieve all descendants of the $r

我正在尝试使用PHP创建一个简单的无序列表菜单。该列表是从MySQL填充的。我很难找到符合我具体需要的说明

要求

我试图避免使用自引用函数。 我试图通过一个性能效率查询来实现这一点。 我正在使用一种改进的预排序树遍历算法来显示菜单。 每行必须由列表项标记包围。 必须在节点开始和结束的位置打开和关闭列表 代码:

PHP部分

$topmenu = '';
$nodes=array();
$nlbr = "\n";

// Now, retrieve all descendants of the $root node
$sql="SELECT n.menu_title, n.menu_title, n.menu_url, n.parent_id, n.lft, n.rgt FROM maj_topmenu AS n, maj_topmenu AS p WHERE n.lft BETWEEN p.lft AND p.rgt AND p.parent_id = '0' ORDER BY n.lft";
$result = mysql_query($sql) or die(mysql_error());

$topmenu .= '<ul>' . $nlbr;
while ($row = mysql_fetch_array($result))
{
    if ( ($row['rgt'] - $row['lft']) == 1 )
    {
        // No child elements
        if (sizeof($nodes) == 0)
        {
            // We're at the top with no children
            $topmenu .= '<li>'.$row['lft'].' <a href="'.$row['menu_url'].'">'.$row['menu_title'].'</a> '.$row['rgt'].'</li>' . $nlbr;
            continue;
        }
        else
        {
            // We're in the middle with no children; We'll need to end at least one branch
            $topmenu .= '<li>'.$row['lft'].' <a href="'.$row['menu_url'].'">'.$row['menu_title'].'</a> '.$row['rgt'].'</li>' . $nlbr;
            while (  ($row['rgt'] + 1) - end($nodes) == 0  )
            {
                $topmenu .= '</ul>' . $nlbr;
                array_pop($nodes);
            }

            continue;
        }
    }
    else
    {
        // Start a new branch
        $topmenu .= '<li>'.$row['lft'].' <a href="'.$row['menu_url'].'">'.$row['menu_title'].'</a> '.$row['rgt'].'</li>' . $nlbr;
        $topmenu .= '<ul>' . $nlbr;

        // End leaf at this point later
        $nodes[] = $row['rgt'];
    }
}
$topmenu .= '</ul>';
我遇到的问题是循环没有在正确的位置结束节点。如果我在第三级分支,它可能会结束太多或太少的列表


这个脚本以后可能会用于广泛的层次结构数据,这就是为什么我选择了MPTTA,我试图避免在多个层次上进行查询。

我编辑了这个答案以改进它

它使用一个sql查询而不是三个sql查询

使用顺序,这样你就可以确信前序旅行是受尊重的,这意味着你只能通过编辑级别和顺序来定义遍历路径,将级别视为自上而下的移动和按左向右移动的顺序。 …列表项标记。。你是说像1.1、1.2之类的东西吗。。。如果是这样的话,那就完了

…节点开始和结束的位置。。。你的意思是说基准面上的标高已经完全显示出来了吗, 而其他层面则不是,它们很接近,如果是这样的话,也没关系

…自我参考。。。如果你指的是调用self的函数,我真的看不出来 发生这种情况的地方包括编辑前的代码??!这里的链接可以按照您的意愿格式化和使用

每次加载页面时,都会执行level函数,如果您根本不希望这种情况发生或经常发生,那么可以使用http请求-ajax

或者,您可以使用自定义缓存,例如,在会话中存储菜单内容,或者从一页转到另一页您无论如何都要支付的通信费用,多加载一点文本不会影响菜单内容,如果当前链接处于同一级别,则使用缓存菜单,如果不是,则运行新查询。这样可以减少数据库通信

  <?php


// Make a MySQL Connection
mysql_connect("localhost", "root", "") or die(mysql_error());

//select database
mysql_query("drop database if exists `my_test`;")or die(mysql_error());  
mysql_query("create database `my_test`;")or die(mysql_error());  
mysql_select_db("my_test") or die(mysql_error());

//create table 
mysql_query(" drop table if exists `menu_item`;")or die(mysql_error());  
mysql_query("   
CREATE TABLE `menu_item` (
    `item_id` MEDIUMINT(8) UNSIGNED NOT NULL  ,
    `item_title` VARCHAR(100) NOT NULL ,
    `item_url` VARCHAR(200)   NULL  ,
    `item_level` TINYINT UNSIGNED NOT NULL   ,
    `order` TINYINT UNSIGNED NOT NULL   , 

    PRIMARY KEY (`item_id`) 
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB;") or die(mysql_error());  





 mysql_query("INSERT INTO `menu_item`  
VALUES (0, 'titile_000', 'http://www', 0, 0  ) ") or die(mysql_error());   
 mysql_query("INSERT INTO `menu_item`  
VALUES (1, 'titile_111', 'http://www', 0, 1  ) ") or die(mysql_error());   
 mysql_query("INSERT INTO `menu_item`  
VALUES (2, 'titile_222', 'http://www', 0, 2  ) ") or die(mysql_error());  
 mysql_query("INSERT INTO `menu_item`  
VALUES (3, 'titile_333', 'http://www', 0, 3  ) ") or die(mysql_error());  

 mysql_query("INSERT INTO `menu_item`  
VALUES (4, 'titile_444', 'http://www', 1, 0  ) ") or die(mysql_error());  
 mysql_query("INSERT INTO `menu_item`  
VALUES (5, 'titile_555', 'http://www', 1, 1 ) ") or die(mysql_error());  
 mysql_query("INSERT INTO `menu_item`  
VALUES (6, 'titile_666', 'http://www', 1, 2 ) ") or die(mysql_error());  
 mysql_query("INSERT INTO `menu_item`  
VALUES (7, 'titile_777', 'http://www', 1, 3  ) ") or die(mysql_error());  

 mysql_query("INSERT INTO `menu_item`  
VALUES (8, 'titile_888', 'http://www', 2, 0  ) ")  or die(mysql_error());  
 mysql_query("INSERT INTO `menu_item`  
VALUES (9, 'titile_999', 'http://www', 2, 1  ) ") or die(mysql_error());    
 mysql_query("INSERT INTO `menu_item`  
VALUES (10, 'titile_010', 'http://www', 2, 2  ) ") or die(mysql_error());    





function  get_level($level )
{ 

    //get level     
    $result = mysql_query("SELECT `item_title`, `item_url`, `item_level`, `order` FROM `menu_item`  
       where `order` = '0' or `item_level` ='{$level}'  order by  `item_level` , `order` ;")
       or die(mysql_error());   

    $output='<b>_____MENU_____</b><br>';

    while($row = mysql_fetch_row($result)) 
    {
        $prefix=($row[3]==0)?$row[2].'.&nbsp;':'&nbsp;&nbsp;&nbsp;'.$row[2].'.'.$row[3].'&nbsp;'; 
        $output.=  $prefix.$row[0].' | '.$row[1].'<br>'; 
    }
    echo $output;   
}


get_level(0);



?>

1.我试图避免使用自引用函数。2.我试图通过一个性能效率查询来实现这一点。3.我正在使用一种改进的预排序树遍历算法来显示菜单。4.每行必须由列表项标记包围。5.必须在节点开始和结束的位置打开和关闭列表
  <?php


// Make a MySQL Connection
mysql_connect("localhost", "root", "") or die(mysql_error());

//select database
mysql_query("drop database if exists `my_test`;")or die(mysql_error());  
mysql_query("create database `my_test`;")or die(mysql_error());  
mysql_select_db("my_test") or die(mysql_error());

//create table 
mysql_query(" drop table if exists `menu_item`;")or die(mysql_error());  
mysql_query("   
CREATE TABLE `menu_item` (
    `item_id` MEDIUMINT(8) UNSIGNED NOT NULL  ,
    `item_title` VARCHAR(100) NOT NULL ,
    `item_url` VARCHAR(200)   NULL  ,
    `item_level` TINYINT UNSIGNED NOT NULL   ,
    `order` TINYINT UNSIGNED NOT NULL   , 

    PRIMARY KEY (`item_id`) 
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB;") or die(mysql_error());  





 mysql_query("INSERT INTO `menu_item`  
VALUES (0, 'titile_000', 'http://www', 0, 0  ) ") or die(mysql_error());   
 mysql_query("INSERT INTO `menu_item`  
VALUES (1, 'titile_111', 'http://www', 0, 1  ) ") or die(mysql_error());   
 mysql_query("INSERT INTO `menu_item`  
VALUES (2, 'titile_222', 'http://www', 0, 2  ) ") or die(mysql_error());  
 mysql_query("INSERT INTO `menu_item`  
VALUES (3, 'titile_333', 'http://www', 0, 3  ) ") or die(mysql_error());  

 mysql_query("INSERT INTO `menu_item`  
VALUES (4, 'titile_444', 'http://www', 1, 0  ) ") or die(mysql_error());  
 mysql_query("INSERT INTO `menu_item`  
VALUES (5, 'titile_555', 'http://www', 1, 1 ) ") or die(mysql_error());  
 mysql_query("INSERT INTO `menu_item`  
VALUES (6, 'titile_666', 'http://www', 1, 2 ) ") or die(mysql_error());  
 mysql_query("INSERT INTO `menu_item`  
VALUES (7, 'titile_777', 'http://www', 1, 3  ) ") or die(mysql_error());  

 mysql_query("INSERT INTO `menu_item`  
VALUES (8, 'titile_888', 'http://www', 2, 0  ) ")  or die(mysql_error());  
 mysql_query("INSERT INTO `menu_item`  
VALUES (9, 'titile_999', 'http://www', 2, 1  ) ") or die(mysql_error());    
 mysql_query("INSERT INTO `menu_item`  
VALUES (10, 'titile_010', 'http://www', 2, 2  ) ") or die(mysql_error());    





function  get_level($level )
{ 

    //get level     
    $result = mysql_query("SELECT `item_title`, `item_url`, `item_level`, `order` FROM `menu_item`  
       where `order` = '0' or `item_level` ='{$level}'  order by  `item_level` , `order` ;")
       or die(mysql_error());   

    $output='<b>_____MENU_____</b><br>';

    while($row = mysql_fetch_row($result)) 
    {
        $prefix=($row[3]==0)?$row[2].'.&nbsp;':'&nbsp;&nbsp;&nbsp;'.$row[2].'.'.$row[3].'&nbsp;'; 
        $output.=  $prefix.$row[0].' | '.$row[1].'<br>'; 
    }
    echo $output;   
}


get_level(0);



?>