Creating a database-driven hierarchical Structure combined with CMenu and superfish
Note: Please also take a look at the newer [EMenu extension](http://www.yiiframework.com/extension/emenu "Title"). This works even better that
the deprecated CDropDownMenu!
In this tutorial we will create a hierarchical Structure using the traditional adjacency list model. Yii's ActiveRecord paradigm makes it very easy to implement this structure via a join on itself. After this, we will use the new CMenu from yii 1.1 and implement it in conjunction with [superfish](http://users.tpg.com.au/j_birch/plugins/superfish/ "Title"), a jQuery plugin for creating menus.
The [CDropDownMenu extension](http://www.yiiframework.com/extension/cdropdownmenu "Title") will help us to accomplish this task.[...]
The 'parent' field contains the id of the direct parent, while 'sort' defines, where our row gets displayed in the menu.
After that, we generate the model and a C-R-U-D interface:
~~~
$ php protected/yiic shell
Yii Interactive Tool v1.1 (based on Yii v1.1.0)
Please type 'help' for help. Type 'exit' to quit.
>> model Hierarchy
>> crud Hierarchy
~~~
When this commands run without an error using [Gii](http://www.yiiframework.com/doc/guide/1.1/en/topics.gii).
Once the model is ready, we should add two relation rules to
our new created modelit:
```php
public function relations()
{
return array(
'getparent' => array(self::BELONGS_TO, 'Hierarchy', 'parent'),
'childs' => array(self::HAS_MANY, 'Hierarchy', 'parent', 'order' => 'sort ASC'),
);
}
```
This reads as: the 'parent' of a row belongs to the parent-column of the same table, while we can gather the childs of a row by a relation of ourself with the
`HAS_MANY
` relation. We always want our childs get ordered by the column 'sort's. You can add additional relations if you want.
To test our newly created model, we need to insert some random test data:[...]
```php
$model = Hierarchy::model()->findByPk(7);
$parent = $model->getparent;
echo $parent->title;
// returns 'First Entry'[...]
$subitems = array();
if($this->childs) foreach($this->childs as $child) {
$subitems[] = $child->getListed();
}
$returnarray = array('label' => $this->
headlintitle, 'url' => array('Hierarchy/view', 'id' => $this->id));
if($subitems != array())
$returnarray = array_merge($returnarray, array('items' => $subitems));
return $returnarray;
}
}
```
We place this function in
`models/Hierarchy.php
`
This is a recursive function (note how the function calls itself) that gathers all subchilds of an element that are available[...]
$items[] = $model->getListed(); // note that the [] is important, otherwise CMenu will crash.
$this->widget('zii.widgetapplication.extensions.CDropDownMenu',array(
'items'=>$items,
));
```
to render the menu with the content of our database.[...]
After this, we want our Users to be able to easily move Menu entries around. To achieve this, we will use a Drop-Down List,
in which we can choose the parent of our selected element. We write this code-snippet to `views/Hierarchy/_form.php
`:[...]
$data = Hierarchy::model()->findAll('parent=:parent', array('parent' => '0'));
foreach($data as $child) {
$subchilds = $child->childs;
foreach($subchilds as $subchild) {
$subchild->title = $subchild->getparent->title . "|" . $subchild->title;
$data = array_merge($data, $child->childs);
}
}
$rootobj = new Hierarchy;
$rootobj->id = 0;
$rootobj->title = "root level";
$root = array($rootobj);
$data = array_merge($root, $data);
if(isset($model->id) && $model->id == 1) {
echo "This is the root node and can't be moved.";
$model->parent = 0;
}
else {
if(isset($_GET['hierarchyParent']))
echo CHtml::DropDownList('Hierarchy[parent]', $_GET['HierarchyParent'], CHtml::listData($data, 'id', 'title'));
else if($update)
echo CHtml::DropDownList('Hierarchy[parent]', $model->parent, CHtml::listData($data, 'id', 'title'));
else
echo CHtml::DropDownList('Hierarchy[parent]', 1, CHtml::listData($data, 'id', 'title'));
}
}
```[...]
if(isset($_GET['hierarchyParent']))
echo CHtml::DropDownList('Hierarchy[parent]', $_GET['HierarchyParent'], CHtml::listData($data, 'id', 'title'));
```
With this lines we will be able to create a "add entry to this element"-Button like this:[...]
```php
if(!Yii::app()->User->isguest)
echo CHtml::link("Add a new element", array('Hierarchy/create', 'hierarchyParent' => $model->id));
```
Place this lines somewhere at
`views/Hierarchy/view.php
`.
I hope my small tutorial was helpful for you. There are some points that can be made even better, for example someone could change the admin CGridView to be collapsable, and the elements could be moved around by drag & drop. In the next version of this Tutorial i will use the nestedset extension to achieve the Hierarchy Structure. Thank you for reading & trying, and
don't hesitate to ask me when you have Questions.