Рекурсивное построение меню

hell0w0rd

Продвинутый новичок
Помогите пожалуйста сделать правильно и желательно красиво, долго пробовал сам, но никак не получается, вот что вышло:
PHP:
public function processMenuData($group, $list){
		$menu = "<ul id='".$group['cssid']."''>";
		foreach ($list as $key => $value){
			$submenu = "";
			if($value['parent']==0){
				$menu .= "<li>";
				$menu .= "<a href='".$value['href']."' title='".$value['title']."'>".$value['name']."</a>";
				foreach ($list as $subkey => $subvalue) {
					if($subvalue['parent']==$value['id']){
						$submenu .= "<li><a href='".$subvalue['href']."' title='".$subvalue['title']."'>".$subvalue['name']."</a></li>";
					}
				}
				if($submenu!="") $menu .= "<ul class='submenu'>".$submenu."</ul>";
				$menu .= "</li>";
			}
		}
		$menu .= "</ul>";
		return $menu;
	}
Так выглядит тестовый массив $list:
PHP:
Array
(
    [0] => Array
        (
            [id] => 1
            [name] => Главная
            [href] => /
            [title] => Главная
            [group] => 1
            [parent] => 0
        )

    [1] => Array
        (
            [id] => 2
            [name] => Каталог
            [href] => 
            [title] => Каталог товаров
            [group] => 1
            [parent] => 0
        )

    [2] => Array
        (
            [id] => 6
            [name] => О нас
            [href] => 
            [title] => О нас
            [group] => 1
            [parent] => 0
        )

    [3] => Array
        (
            [id] => 7
            [name] => Фотоальбом
            [href] => /photo
            [title] => Фотоальбом
            [group] => 1
            [parent] => 6
        )

    [4] => Array
        (
            [id] => 8
            [name] => Контакты
            [href] => /contacts
            [title] => Контакты
            [group] => 1
            [parent] => 6
        )

    [5] => Array
        (
            [id] => 9
            [name] => Бублики
            [href] => /catalog/1
            [title] => Бублики
            [group] => 1
            [parent] => 2
        )

    [6] => Array
        (
            [id] => 10
            [name] => Пряники
            [href] => /catalog/2
            [title] => Пряники
            [group] => 1
            [parent] => 2
        )

    [7] => Array
        (
            [id] => 11
            [name] => Тульские
            [href] => /сatalog/2/1
            [title] => Тульские
            [group] => 1
            [parent] => 10
        )

)
Подменю с Тульские ясное дело не выводится, потому что нет рекурсивного вывода подменю, пожалуйста помогите доработать
 

Фанат

oncle terrible
Команда форума
Когда-то давно я написал такой вот ужас.
Вряд ли он будет тебе интересен, но все равно никто больше не отвечает.
К тому же он исправно работал, выводя все дерево красивой лесенкой.

чтобы было чуть понятнее - он сначала получает древовидный массив, а потом раскатывает его в одномерный, с маркерами начала/конца ветки.
PHP:
<?php

function get_tree($parent=0,$level=0) {
  static $ret;
  $res=mysql_query("SELECT id,title FROM menu WHERE parent=".intval($parent)." ORDER BY id");
  if (!mysql_num_rows($res)) return array();
  while($row=mysql_fetch_assoc($res)) {
    $row['level']=$level;
    $ret[$row['id']]=$row;
    get_tree($row['id'],$level+1);
  }
  return $ret;
}

$TREE=get_tree();
$oldlev=-1;
foreach($TREE as $k => $row) {
  $delta=$oldlev-$row['level'];
  if($delta >  0) {
    $row['li']='close';
    for($i=0;$i<$delta-1;$i++) $tmp[]=array('id'=>0,'li'=>'close');
  }
  if($delta <  0) $row['li']='open';
  if($delta == 0) $row['li']='same';
  $tmp[]=$row;
  $oldlev=$row['level'];
}
$TREE=$tmp;
?>
<table border=1 cellpadding=10><tr><td>
<a href="?id=0">Add root item</a><br>
<? foreach ($TREE as $item): ?>
<? if($item['li']=="open"): ?><ul><?endif?>
<? if($item['li']=="close"): ?></ul><?endif?>
<? if($item['id']!=0): ?>
<? if($id==$item['id']): ?>
<li>
<?=$row['title']?>
<a href="?id=0&parent=<?=$item['id']?>">[Add]</a>
</li>
<? else: ?>
<li>
<a href="?id=<?=$item['id']?>"><?=$item['title']?></a>
</li>
<?endif?>
<?endif?>
<? endforeach ?>
</ul>
 

SANEK333

Новичок
PHP:
<?
class menu
 {
  public function processMenuData($group,$list,$id=0)
   {
    $menu=false;
    $childs=$list;
    foreach ($list as $key=>$value)
     if ($value['parent']==$id)
      {
       if (!$menu)
        $menu=$id?"<ul class='submenu'>":"<ul id='".$group['cssid']."'>";
       unset($childs[$key]);
       $menu.= "<li>";
       $menu.= "<a href='".$value['href']."' title='".$value['title']."'>".$value['name']."</a>";
       $sub=$this->processMenuData($group,$childs,$value['id']);
       if ($sub)
        $menu.=$sub;
       $menu .= "</li>";
      }
    if ($menu)
     $menu .= "</ul>";
    return $menu;
   }
 }
$menu=new menu();
$list=array(
 array(
  'id'=>1,
  'name'=>'item 1',
  'href' =>'1',
  'title' => '1',
  'group' => '1',
  'parent' => 0
 ),
 array(
  'id'=>2,
  'name'=>'item 2',
  'href' =>'2',
  'title' => '2',
  'group' => '1',
  'parent' => 0
 ),
 array(
  'id'=>3,
  'name'=>'item 3',
  'href' =>'3',
  'title' => '3',
  'group' => '1',
  'parent' => 0
 ),
 array(
  'id'=>4,
  'name'=>'item 1_1',
  'href' =>'1_1',
  'title' => '1_1',
  'group' => '1',
  'parent' => 1
 ),
 array(
  'id'=>5,
  'name'=>'item 1_2',
  'href' =>'1_2',
  'title' => '1_2',
  'group' => '1',
  'parent' => 1
 ),
 array(
  'id'=>6,
  'name'=>'item 2_1',
  'href' =>'2_1',
  'title' => '2_1',
  'group' => '1',
  'parent' => 2
 ),
 array(
  'id'=>7,
  'name'=>'item 2_1_1',
  'href' =>'2_1_1',
  'title' => '2_1_1',
  'group' => '1',
  'parent' => 6
 ),
 array(
  'id'=>8,
  'name'=>'item 2_1_2',
  'href' =>'2_1_2',
  'title' => '2_1_2',
  'group' => '1',
  'parent' => 6
 ));
echo $menu->processMenuData(array('cssid'=>'test'),$list);
?>
 

hell0w0rd

Продвинутый новичок
Не особо помог ваш скрипт, однако роением инета вот что сделал, скрипт - решение проблемы:
PHP:
public function processMenuData($group, $list, $lvl=0){
		$menu = "<ul id='".$group['cssid']."''>";
		foreach ($list as $key => $value){
			$submenu = "";
			if($value['parent']==$lvl){
				$menu .= "<li>";
				$menu .= "<a href='".$value['href']."' title='".$value['title']."'>".$value['name']."</a>";
				$submenu .= $this->processMenuData($group, $list, $value['id']);
				if($submenu!="") $menu .= "<ul class='submenu'>".$submenu."</ul>";
				$menu .= "</li>";
			}
		}
		$menu .= "</ul>";
		return $menu;
	}
 

Фанат

oncle terrible
Команда форума
"не особо помог" в каком смысле?
основная идея скрипта была в том, чтобы вынести оформление в шаблон. если тебе, конечно, известно такое слово.
 

SANEK333

Новичок
Не особо помог ваш скрипт, однако роением инета вот что сделал, скрипт - решение проблемы:
PHP:
public function processMenuData($group, $list, $lvl=0){
		$menu = "<ul id='".$group['cssid']."''>";
		foreach ($list as $key => $value){
			$submenu = "";
			if($value['parent']==$lvl){
				$menu .= "<li>";
				$menu .= "<a href='".$value['href']."' title='".$value['title']."'>".$value['name']."</a>";
				$submenu .= $this->processMenuData($group, $list, $value['id']);
				if($submenu!="") $menu .= "<ul class='submenu'>".$submenu."</ul>";
				$menu .= "</li>";
			}
		}
		$menu .= "</ul>";
		return $menu;
	}
в вашем скрипте 2-й ul будет <ul class='submenu'><ul id='".$group['cssid']."''> что ваще не камельфо
 

craz

Нестандартное звание
почему все бояться посоветовать nested sets?
 

hell0w0rd

Продвинутый новичок
Конечно известно, я не коем образом не хотел задеть тебя этим сообщением)
Данная функция - класса представления, из модели как раз берутся $list и $group, если можете - пожалуйста помогите усовершенствовать итоговую функцию:
PHP:
public function processMenuData($group, $list, $lvl=0){
		$menu = "<ul id='".$group['cssid']."-$lvl'>";
		foreach ($list as $key => $value){
			$submenu = "";
			if($value['parent']==$lvl){
				$menu .= "<li>";
				$menu .= "<a href='".$value['href']."' title='".$value['title']."'>".$value['name']."</a>";
				$menu .= $this->processMenuData($group, $list, $value['id']);
				$menu .= "</li>";
			}
		}
		$menu .= "</ul>";
		return $menu;
	}
Вот первая строка, ясно что пустого ула тут быть не должно, проверку какую-то добавить надо?
<li>
<a href="/" title="Главная">Главная</a>
<ul id="firstmenu-1"></ul>
</li>
 

hell0w0rd

Продвинутый новичок
PHP:
if($menu=="<ul id='".$group['cssid']."-$lvl'></ul>") $menu="";
Решил проблему такой проверкой перед return $menu; если будут другие идеи - пожалуйста подскажите)
 

SANEK333

Новичок
PHP:
public function processMenuData($group,$list,$id=0)
   {
    $menu=false;
    $childs=$list;
    foreach ($list as $key=>$value)
     if ($value['parent']==$id)
      {
       if (!$menu)
        $menu=$id?"<ul class='submenu'>":"<ul id='".$group['cssid']."'>";
       unset($childs[$key]);
       $menu.= "<li>";
       $menu.= "<a href='".$value['href']."' title='".$value['title']."'>".$value['name']."</a>";
       $sub=$this->processMenuData($group,$childs,$value['id']);
       if ($sub)
        $menu.=$sub;
       $menu .= "</li>";
      }
    if ($menu)
     $menu .= "</ul>";
    return $menu;
   }
оо, где громоздкость?
 

Redjik

Джедай-мастер
почему все бояться посоветовать nested sets?
потому, что пока найдешь толковый класс-обертку или напишешь сам успеешь два раза сделать adjacency =)
по крайней мере для вывода меню, которое все равно в кеше должно быть - это вполне оправдано.
 

hell0w0rd

Продвинутый новичок
вообще - имеют.
но мы говорим про конкретно твой код, в котором шаблонами и не пахнет
Интересное у тебя мнение о коде, который даже не видишь, а видишь лишь одну функцию одного класса)
В итоге всем спасибо за помощь)
 

Фанат

oncle terrible
Команда форума
так этого достаточно же.
если бы ты понимал, что такое шаблоны - тебе тоже было бы очевидно.
 

Фанат

oncle terrible
Команда форума
Нет, не понимаешь.
вот это -
PHP:
$menu.= "<a href='".$value['href']."' title='".$value['title']."'>".$value['name']."</a>";
- к шаблонам не имеет ни малейшего отношения.
Это называется "спагетти".
интересно как тебе видится препроцессор подобного шаблонизатора
Меня тут одна мысль озарила.
Скажи, употребляя слово "препроцессор", не имеешь ли ты в виду, что вот этот вот код генерирует код шаблона со смартиподобным иснтаксисом?
 
Сверху