2011-06-03 212 views
0

我正在嘗試使用PHP創建一個簡單的無序列表菜單。該列表從MySQL填充。我很難找到符合我特定需求的說明。簡單的PHP菜單與MPTTA層次

要求

  1. 我試圖避免自我參照的功能。
  2. 我想用一個查詢來提高性能。
  3. 我正在使用修改的預定樹遍歷算法來顯示菜單。
  4. 每行必須被列表項標記包圍。
  5. 列表必須打開和關閉,其中節點開始和結束

代碼:

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進行此操作的原因,並且我試圖避免必須在多個級別進行查詢。

回答

0

我已編輯此答案以改善此問題。

  1. 它使用一個SQL查詢,而不是三個

  2. 它使用「排序依據」所以你一定預購行程的尊重,這意味着你只能通過編輯水平和順序確定遍歷路徑,考慮級別爲自上而下,並且從左至右移動。

  3. ..list item tag ..你的意思是像1.1,1.2等東西...如果是這樣的話,那麼就完成了。

  4. ..其中節點開始和結束...您的意思是參考水平完全顯示, 和其他級別不(他們是接近的),如果這種情況沒關係。

  5. ..自己參考...如果你的意思是自己調用它的函數,我真的看不到 發生這種情況(包括編輯前的代碼)??!這裏的鏈接可以按照你的意願進行格式化和使用!

每次加載頁面時,都會執行關卡函數,如果您不希望發生這種情況,或者經常可以使用http請求 - ajax!

或者您可以使用自定義緩存,例如在會話中存儲菜單內容,或者從一個頁面到另一個頁面進行傳輸(無論如何,您支付的通信費用,加載了更多文本都沒有區別)菜單內容,則if當前鏈接與使用緩存菜單的級別相同,如果不是,則運行新查詢。這樣你可以減少數據庫通信。

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



?> 
+0

1.我試圖避免自引用函數。 ** 2。我試圖用一個查詢來提高性能效率。** ** 3。我正在使用修改的預定樹遍歷算法來顯示菜單。** ** 4。每行必須被列表項標籤包圍。** ** 5。列表必須在節點開始和結束時打開和關閉** – Tanoro 2011-06-06 14:58:42