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

时间:2011-06-03 18:08:03

标签: php mysql menu

我正在尝试使用PHP创建一个简单的无序列表菜单。该列表是从MySQL填充的。我在查找符合我特定需求的说明时遇到了很多麻烦。

要求

  1. 我试图避免自我引用功能。
  2. 我试图通过一个查询来提高效率。
  3. 我使用修改后的预先排序的树遍历算法来显示菜单。
  4. 每行必须包含列表项标记。
  5. 必须在节点开始和结束的地方打开和关闭列表
  6. 代码:

    CREATE TABLE IF NOT EXISTS `maj_topmenu` (
    `menu_id` int(11) NOT NULL auto_increment,
    `menu_title` varchar(100) NOT NULL default '',
    `menu_url` varchar(200) NOT NULL default '',
    `menu_level` int(10) NOT NULL default '0',
    `parent_id` int(11) NOT NULL default '0',
    `lft` int(10) NOT NULL,
    `rgt` int(10) NOT NULL,
    `displayorder` int(11) default NULL,
    PRIMARY KEY  (`menu_id`)
    ) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=8 ;
    
    INSERT INTO `maj_topmenu` (`menu_id`, `menu_title`, `menu_url`, `menu_level`, `parent_id`, `lft`, `rgt`, `displayorder`) VALUES
    (1, 'Home', '/home', 0, 0, 1, 2, 0),
    (2, 'About Us', '/about', 0, 0, 5, 10, 10),
    (3, 'News', '/news', 0, 0, 3, 4, 5),
    (4, 'Blogs', '/viewblog', 0, 0, 11, 12, 15),
    (5, 'Contact Us', '/contact', 0, 0, 13, 14, 20),
    (6, 'Sub Menu 1', '/link1', 1, 2, 6, 9, 0),
    (7, 'Sub Menu 2', '/link2', 2, 6, 7, 8, 0);
    

    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,我试图避免在多个级别进行查询。

1 个答案:

答案 0 :(得分:0)

我已编辑此答案以改进它。

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

  2. 它使用“order by”,因此您可以确保预订行程得到尊重,这意味着您只能通过编辑级别和顺序来定义遍历路径,将级别视为自上而下移动并将顺序视为向左移动右。

  3. ..列表项标签..你的意思是1.1,1.2等......如果是这样的话就完成了。

  4. ..节点开始和结束的位置......你的意思是完全显示参考水平, 和其他级别不一样(它们很接近),如果是这样的话就可以了。

  5. ..自我引用...如果你的意思是自称的功能,我真的看不到 发生这种情况(包括编辑前的代码)??!这里的链接可以按照您的意愿格式化和使用!

  6. 每次加载页面时都会执行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);
    
    
    
    ?>