Мне наконец удалось, ничего не изменив.Я был немного вдохновлен линейным хранилищем по ссылке и 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 '
';?>