2011-12-27 75 views
0
  1. 我得到存儲在一個分貝這樣嵌套陣列來創建笨下拉

    INSERT INTO `mycms_menus` (`menu_id`, `title`, `pos`, `parent_menu_id`) VALUES 
        (1, 'Menu principal', 0, 0), 
        (2, 'Menu secondaire', 0, 0), 
        (3, 'SUBMENU 1-1', 0, 1), 
        (4, 'SUBMENU 2-1', 0, 2), 
        (5, 'SUBMENU 1-2', 0, 1), 
        (6, 'SUBMENU 2-2', 0, 2), 
        (7, 'submenu 2-3', 0, 2), 
        (10, 'submenu 1-2-1', 0, 5); 
    
  2. 我使用的函數將其轉換爲一個嵌套陣列(multidim)菜單

    function _flat_to_nested($source) 
    { 
    $nodes = array(); 
    $tree = array(); 
    foreach ($source as &$node) { 
        $node->children = array(); 
        $id = $node->menu_id; 
        $parent_id = $node->parent_menu_id; 
        $nodes[$id] =& $node; 
         if (array_key_exists($parent_id, $nodes)) { 
          $nodes[$parent_id]->children[] =& $node; 
         } else { 
          $tree[] =& $node; 
         } 
        } 
    
        return $tree; 
    
    } 
    

它返回一個結構陣列,如:

Array 
    (
     [0] => stdClass Object 
      (
       [menu_id] => 1 
       [title] => Menu principal 
       [pos] => 0 
       [parent_menu_id] => 0 
       [children] => Array 
        (
         [0] => stdClass Object 
          (
           [menu_id] => 3 
           [title] => SUBMENU 1-1 
           [pos] => 0 
           [parent_menu_id] => 1 
           [children] => Array 
            (
            ) 

          ) 

         [1] => stdClass Object 
          (
           [menu_id] => 5 
           [title] => SUBMENU 1-2 
           [pos] => 0 
           [parent_menu_id] => 1 
           [children] => Array 
            (
             [0] => stdClass Object 
              (
               [menu_id] => 10 
               [title] => submenu 1-2-1 
               [pos] => 0 
               [parent_menu_id] => 5 
               [children] => Array 
                (
                ) 

              ) 

            ) 

          ) 

        ) 

      ) 

     [1] => stdClass Object 
      (
       [menu_id] => 2 
       [title] => Menu secondaire 
       [pos] => 0 
       [parent_menu_id] => 0 
       [children] => Array 
        (
         [0] => stdClass Object 
          (
           [menu_id] => 4 
           [title] => SUBMENU 2-1 
           [pos] => 0 
           [parent_menu_id] => 2 
           [children] => Array 
            (
            ) 

          ) 

         [1] => stdClass Object 
          (
           [menu_id] => 6 
           [title] => SUBMENU 2-2 
           [pos] => 0 
           [parent_menu_id] => 2 
           [children] => Array 
            (
            ) 

          ) 

         [2] => stdClass Object 
          (
           [menu_id] => 7 
           [title] => submenu 2-3 
           [pos] => 0 
           [parent_menu_id] => 2 
           [children] => Array 
            (
            ) 

          ) 

        ) 

      ) 

    ) 

3.but我在這裏停留,因爲我需要這個嵌套數組將在form_dropdown從codeigniter html helper使用,需要一個類似的數組,但具有不同結構的轉換一樣:

$options = array(
     'menu_id' => 'menu title', 
     '##' => 'text', 
     'optgroup text' => array(
      'menu_id' => 'menu title', 
      '##' => 'text', 
      ), 
     ), 
    ); 
    echo form_dropdown('name',$options,null) 

這將轉換將嵌套數組嵌入到具有嵌套optgroup的下拉列表中。

我不能成功地將我的表格菜單數據轉換爲嵌套的下拉列表,我可以使用下拉幫助器,所以我希望有人可以給我一個提示或線索來實現這一點。 thanx提前 林」知道,我可能會重寫整個過程中這樣做,所以任何想法是值得歡迎的

回答

0

我終於成功了,而不改變沒有。我受到了鏈接和xpath中線性存儲的啓發。

這裏是我結束的課程(有些代碼不是來自我)。這只是一個基地,我沒有在其他項目中測試過,所以它可能包含錯誤或不爲你做這項工作,但你可以試試。

它將平面數組轉換爲不同類型的multidim /嵌套數組。包括轉換爲html下拉列表和html列表:

對不起,這是很多的代碼。

編輯:經過一些更多的測試後,嵌套optgroups將不會由瀏覽器呈現預期,所以我不建議去與嵌套opgroups。我將切換到與一些CSS結合的單選按鈕。

<?php 
    /** 
    * 
    * CLASS 
    * ********************************************************************* 
    * several functions to convert a menu, from a FLAT array into a MULTIDIM/NESTED array 
    * or into an HTML dropdown OR HTML list 
    * ********************************************************************* 
    ** ::_flat_to_nested ** convert FLAT into MULTIDIM/NESTED 
    * 
    ** ::_nested_to_ul ** convert MULTIDIM/NESTED into HTML LIST 
    * 
    ** ::_nested_to_dropdown ** convert MULTIDIM/NESTED into HTML SELECT/OPTGROUP/OPTION 
    * no nested optgroup allowed 
    * <optgroup> tag can only contains <options> tags = w3c standards 
    * 
    ** ::_nested_to_dropdown_html ** convert MULTIDIM/NESTED into HTML SELECT/OPTGROUP/OPTION 
    * multiple nested optgroups allowed 
    * 

    * USAGE: 
    * $list = {array of objects} 
    * $t = new myNested; 
    * $result = $t->index($list); 
    * 
    */ 
    class myNested { 

    //results 
    var $parserStrFin=""; 

    //iterations 
    var $it=0; 

    //level 
    var $profondeur=0; 


    /** 
    * convert flat array into ... 
    * 
    * @return several formatted arrays 
    */ 
    function index($list=array()) 
    { 

     $nested = $this->_flat_to_nested($list); 
     $dropdown = $this->_nested_to_dropdown_html($nested); 
     $dropdown2 = $this->_nested_to_dropdown($nested); 
     $htmlist = $this->_nested_to_ul($nested); 


     //trick to convert recursivelly all objects into arrays 
     // $dropdown = json_decode(json_encode($dropdown), true); 
     // $dropdown2 = json_decode(json_encode($dropdown2), true); 

     return array(
     'list'  => $list, 
     'nested' => $nested, 
     'dropdown' => $dropdown, 
     'dropdown2' => $dropdown2, 
     'htmlist' => $htmlist, 
    ); 
    } 


    /** 
    * 
    * convert MULTIDIM/NESTED into HTML SELECT/OPTGROUP/OPTION 
    * no nested optgroup allowed 
    * <optgroup> tag can only contains <options> tags = w3c standards 
    * 
    * @param array $array 
    * @param bool $_autoCall 
    * @param int $profondeur 
    * @param int $it 
    * @return str html string to use into <select> tag 
    */ 
    private function _nested_to_dropdown($array=array(), $_autoCall=false, $profondeur="", $it=0) 
    { 

     //first call, reset 
     if (!$_autoCall) 
     { 
     $this->fin=array(); 
     $this->root=null; 
     $this->it=0; 
     $this->profondeur=0; 
     $this->xpath=""; 
     $this->parserStrFin=""; 
     } 

     //items count 
     $this->it++; 


     //dim after dim 
     foreach($array as $value) 
     { 

     if (count($value->children)>0) 
     { 
      //if item contains children 
      $this->profondeur++; 

      if (!$this->root) { 
      $this->root =& $this->fin;//change current node 
      } 

      $this->root[$value->title] = array();//prep optgroup 

      $this->xpath .= $value->title."/"; //linear path 

      $this->root = & $this->root[$value->title]; //define this node as root 

      $this->root[$value->menu_id] = $value->title;//the optgroup is added as a normal option to be selectable 

      $this->_nested_to_dropdown($value->children, true, $this->profondeur, $this->it);//process with children 
     } 
     elseif (count($value->children)==0 && isset($value->title)) { 

      //items without children 
      //title is a string, without chukd: extremity reached 
      $this->root[$value->menu_id] = $value->title; //each child as new option 

     } 

     }//foreach 


     //after an item without children is added 
     // returns one dim up 
     if ($this->profondeur) { 
     $this->profondeur--; 

     $regs=array(); 
     $regs = explode('/',$this->xpath); 
     $regs = array_filter($regs);//clear empty values 

     //one dim up in the path 
     $regs = array_slice($regs, 0, $this->profondeur); 


     if ($regs) { 

      //goes from dim 0 to dim ## 
      $n =& $this->fin; 
      foreach ($regs as $v) { 
      $n =& $n[$v];//fin[lv1], puis fin[lv1][lv2] 
      } 


      //set the new root for next items 
      $this->root = & $n; 

      //xpath 
      $this->xpath=implode('/',$regs);//reset 

     } 
     else{ 
      //reset 
      $this->root =& $this->fin; 
      $this->xpath=''; 
     } 

     } 

     return $this->fin; 
    } 


    /** 
    * 
    * convert MULTIDIM/NESTED into HTML SELECT/OPTGROUP/OPTION 
    * multiple nested optgroups allowed ! 
    * 
    * @param <array> $array 
    * @param <bool> $_autoCall 
    * @param <str/int> $profondeur 
    * @param <int> $it 
    * @return <str> html string 
    * 
    **/ 
    function _nested_to_dropdown_html($array=array(), $_autoCall=false, $profondeur="", $it=0) 
    { 

     if (!$_autoCall) 
     { 
     $this->parserStrFin=""; 
     $this->it=0; 
     $this->profondeur=0; 
     } 

     $this->it++; 

     foreach($array as $value) 
     { 

     if (count($value->children)>0) 
     { 
      $p = 15 * $this->profondeur;//or in your .css: optgroup>optgroup {padding-left: 15px}; 
      $this->profondeur++; 
      $this->parserStrFin .= '<optgroup class="submenu-title" style="padding-left:'.$p.'px" label="'.$value->title.'">'."\n"; 
      $this->parserStrFin .= ' <option class="submenu-item" value="'.$value->menu_id.'">'.$value->title.'</option>'."\n"; 
      $this->_nested_to_dropdown_html($value->children, true, $this->profondeur, $this->it); 
     } 
     elseif (count($value->children)==0 && isset($value->title)) { 
      $this->parserStrFin .= ' <option class="submenu-item" value="'.$value->menu_id.'">'.$value->title.'</option>'."\n"; 

     } 

     } 

     if ($this->profondeur)  { $this->parserStrFin .= '</optgroup>'."\n"; $this->profondeur--; } //prof = 0, on ferme le UL FirstLevelListTypeTag 

     return $this->parserStrFin; 
    } 



    /** 
    * convett FLAT en MULTIDIM/NESTED 
    * 
    * @param array flat $list 
    * @return array multi 
    * @source: php.net 
    * 
    * NOTE: array must be well sorted: parents items must be parsed before any of their child 
    */ 
    private function _flat_to_nested($source) 
    { 
     $nodes = array(); 
     $tree = array(); 
     foreach ($source as &$node) { 
     $node->children = array(); 
     $id = $node->menu_id; 
     $parent_id = $node->parent_menu_id; 
     $nodes[$id] =& $node; 
     if (array_key_exists($parent_id, $nodes)) { 
      $nodes[$parent_id]->children[] =& $node; 
     } else { 
      $tree[] =& $node; 
     } 
     } 

     return $tree; 

    } 



    /** 
    * convert MULTIDIM/NESTED into HTML LIST 
    * 
    * @param array $array 
    * @param bool $_autoCall 
    * @param int $profondeur 
    * @param int $it 
    * @return <str> html list 
    * 
    **/ 
    function _nested_to_ul($array=array(), $_autoCall=false, $profondeur="", $it=0) 
    { 

     if (!$_autoCall) 
     { 
     $this->parserStrFin=""; 
     $this->it=0; 
     $this->profondeur=0; 
     } 

     $firstListType = 'ul';//first level list type 
     $itemsListType = 'ul';//sub level list type 

     $tag = (empty($this->profondeur) && $this->it==0) ? $firstListType : $itemsListType; 
     $this->parserStrFin .= "\n".'<'.$tag.' class="level-'.$this->profondeur.'">'."\n"; 

     $this->it++; 

     foreach($array as $value) 
     { 

     if (count($value->children)>0) 
     { 
      $this->profondeur++; 
      $this->parserStrFin .= ' <li class="submenu-title"><h3>'. $value->title .'</h3>'."\n"; 
      $this->_nested_to_ul($value->children, true, $this->profondeur, $this->it); 
     } 
     elseif (count($value->children)==0 && isset($value->title)) { 
      $this->parserStrFin .= ' <li class="submenu-item">'. '<a href="#'.$value->menu_id.'">'.$value->title.'</a>' .'</li>'."\n"; 

     } 

     } 


     if ($this->profondeur == 0)  { $this->parserStrFin .= "</".$firstListType.">\n"; $this->profondeur--; } 
     else if (($this->profondeur > 0)) { $this->parserStrFin .= "</".$itemsListType.">\n</li>\n"; $this->profondeur--; } 

     return $this->parserStrFin; 
    } 

    } 

    //SAMPLE USAGE: 

    //DATAS: 
    //the class uses FLAT array containing "objects" so here's the datas 
    $list='a:8:{i:0;O:8:"stdClass":4:{s:7:"menu_id";s:1:"1";s:5:"title";s:14:"Menu principal";s:3:"pos";s:1:"0";s:14:"parent_menu_id";s:1:"0";}i:1;O:8:"stdClass":4:{s:7:"menu_id";s:1:"2";s:5:"title";s:15:"Menu secondaire";s:3:"pos";s:1:"0";s:14:"parent_menu_id";s:1:"0";}i:2;O:8:"stdClass":4:{s:7:"menu_id";s:1:"3";s:5:"title";s:11:"SUBMENU 1-1";s:3:"pos";s:1:"0";s:14:"parent_menu_id";s:1:"1";}i:3;O:8:"stdClass":4:{s:7:"menu_id";s:1:"4";s:5:"title";s:11:"SUBMENU 2-1";s:3:"pos";s:1:"0";s:14:"parent_menu_id";s:1:"2";}i:4;O:8:"stdClass":4:{s:7:"menu_id";s:1:"5";s:5:"title";s:11:"SUBMENU 1-2";s:3:"pos";s:1:"0";s:14:"parent_menu_id";s:1:"1";}i:5;O:8:"stdClass":4:{s:7:"menu_id";s:1:"6";s:5:"title";s:11:"SUBMENU 2-2";s:3:"pos";s:1:"0";s:14:"parent_menu_id";s:1:"2";}i:6;O:8:"stdClass":4:{s:7:"menu_id";s:1:"7";s:5:"title";s:11:"submenu 2-3";s:3:"pos";s:1:"0";s:14:"parent_menu_id";s:1:"2";}i:7;O:8:"stdClass":4:{s:7:"menu_id";s:2:"10";s:5:"title";s:13:"submenu 1-2-1";s:3:"pos";s:1:"0";s:14:"parent_menu_id";s:1:"5";}}'; 
    $list=unserialize($list); 

    //EXEC! 
    $t = new myNested; 
    $result = $t->index($list); 

    //RETURNS: 
    $source = $result['list']; 
    $nested = $result['nested']; 
    $dropdown = $result['dropdown']; 
    $dropdown2 = $result['dropdown2']; 
    $htmlist = $result['htmlist']; 

    echo '<pre style="border:1px solid #C00; color: #C00; background:#FFFFFE;">'; 
    echo "<B>SOURCE=</B>:<br/>"; print_r($source); echo "<hr/>"; 
    echo "<B>NESTED=</B>:<br/>"; print_r($nested); echo "<hr/>"; 
    echo "<B>DROPDOWN=</B>:<br/>"; highlight_string($dropdown); echo "<hr/>"; 
    echo "<B>DROPDOWN2=</B>:<br/>"; print_r($dropdown2); echo "<hr/>"; 
    echo "<B>HTMLIST=</B>:<br/>"; print_r($htmlist); echo "<hr/>"; 
    echo '</pre>'; 



    ?> 
1
object[0] 
    =>[0] 
    =>[1] 

...是當前的結構

其工作很多,從這個樹拉(recursivley)...我可以建議另一種方法嗎?!

沒有想到的另一個algoritm,不能現在想起來,它使用LFT和RT指針(啊我的腦子一片空白)...替代你可以嘗試Trees & Hierarchies in SQL

+0

真的很感謝任何建議,歡迎光臨! 我會檢查你的鏈接thanx;) – pit 2011-12-27 23:21:27

+0

你給的鏈接似乎是一個好方法。如果我沒有得到答案,那麼我會嘗試這與存儲血統thanx;) – pit 2011-12-27 23:29:41