Деревья

Всем привет, есть таблица со столбцами id, parent_id, name, пытаюсь вывести список(дерево) учитывая уровень вложенности, покопался в гугле, нашел функцию https://gist.github.com/samdark/3016663, немного дополнил, все получилось, но я почти уверен что есть более красивое решение, чем это:




public function getCatList()

{

	$categories = Category::model()->findAll();


	foreach ($categories as $key => $value)

	{

		if($value->parent_id == 0)

		{

			$cat[$value->id][] = array("parent_id"=>$value->parent_id, "name"=>$value->name);

		}else{

			$cat[$value->parent_id][] = array("parent_id"=>$value->parent_id, "name"=>$value->name);

		}

	}


	krsort($cat);


	$parent_id=0;

		

	foreach ($cat as $key => $value) {

	        foreach ($value as $k => $item) {

			if($item['parent_id']==$parent_id) {

			echo "</li>\n";

		}

		else if($item['parent_id']>$parent_id) {

			echo "<ul>\n";

		}else{

		        echo "</li>\n";

	 

		for($i=$parent_id-$item['parent_id'];$i;$i--) {

		         echo "</ul>\n</li>\n";

	 

		}

	}

	 

	echo "<li>";

	echo $item['name'];

	$parent_id=$item['parent_id'];

	}

	 

	for($i=$parent_id;$i;$i--) {

		echo "</li>\n</ul>\n";

		}

	}

	}



Соответственно получаю




Новости

-Авторынок

-Автопром

-Автожизнь

-Происшествия

-Выставки

BMW

-Acura

Bentley

Audi

Alfa Romeo



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

Можно как то так, если AR и рекурсия:




public function getCategories() {

        $criteria = new CDbCriteria;

        $criteria->order = 'parent ASC';

        $categories = self::model()->findAll($criteria);

        return $this->buildTree($categories);

    }


protected function buildTree(&$data, $rootID = 0) {

        $tree = array();

        foreach ($data as $id => $node) {

            if ($node->parent == $rootID) {

                unset($data[$id]);

                $node->childs = $this->buildTree($data, $node->id);

                $tree[] = $node;

            }

        }

        return $tree;

    }



Обращаться с ним потом так как вам нужно:




$categoriesTree = $this->getCategories();

foreach ($categoriesTree as $category) {

       if ($category->parent == 0) {

           //собственно $category - ваша родительская категория

           //$category->childs - дети

           }

       }



Спасибо, надо будет потестить ради интереса что меньше ресурсов ест, хотя категорий будет не более 100 я думаю :)

Загнулся мой мега код на 3 уровне вложенности, вывел вообще третий уровень в другом месте ;D

Вот собственно вывод самого меню:




public static function getLeveledMenu($genres)

    {

        $output="<ul>";

        foreach($genres as $genre){

            $output.="<li>".$genre->title."</li>";

            if (!empty($genre->childs)){

                $output.=self::getLeveledMenu($genre->childs);

            }

        }

        $output.="</ul>";

        return $output;

    }



На скорую руку писал, но должно работать. У меня немного другая ситуация, у детей еще может быть по несколько родителей, и я записал в таблицу немного не правильно. Возможно сейчас переделаю, или что то придумаю. У меня порядка 600 категорий, отрабатывает быстро.

Спасибо, остановился на рекурсии, а так хотел сделать без нее :-[