вложенный массив для создания выпадающего в codeigniter - PullRequest
0 голосов
/ 27 декабря 2011
  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.но здесь я застрял, потому что мне нужно преобразовать этот вложенный массив для использования в 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)

Это преобразует вложенный массив в выпадающий список с вложенными оптгруппами.

Мне не удалось преобразовать данные моего меню таблицы во вложенный раскрывающийся список, который я могу использовать с помощником раскрывающегося списка, поэтому я хотел бы, чтобы кто-нибудь мог дать мне совет или подсказки для достижения этой цели. спасибо заранее Я знаю, что для этого могу переписать весь процесс, поэтому любая идея приветствуется

Ответы [ 2 ]

1 голос
/ 27 декабря 2011
object[0]
    =>[0]
    =>[1]

... ваша текущая структура

Много работы по извлечению из этого дерева (recursivley) ... Могу ли я предложить другой подход?!

Есть еще одинАлгоритм, который приходит на ум, не могу подумать об этом прямо сейчас, он использует указатели lft и rt (аааа, у меня пусто) ... альтернативно вы можете попробовать Деревья и иерархии в SQL

0 голосов
/ 30 декабря 2011

Мне наконец удалось, ничего не изменив.Я был немного вдохновлен линейным хранилищем по ссылке и xpath, как.

Вот класс, которым я закончил (некоторый код не от меня).Это просто база, я не тестировал ее в других проектах, поэтому она может содержать ошибку или не выполнять работу за вас, но вы можете попробовать.

Он преобразует плоский массив в различные типы multidim/ вложенные массивы.Включая преобразование в раскрывающийся список html и список html:

Извините, кода много.

РЕДАКТИРОВАТЬ: после еще одного тестирования вложенные группы opt не будут отображаться браузером, как ожидается, поэтомуНе рекомендуется использовать вложенные группы.Я переключусь на переключатели в сочетании с некоторыми css.

<code>  <?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 '
';?>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...