CodeIgniter Forums

Full Version: multi level menu with codeigniter
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
I want to create a multi level menu with codeIgniter.

My table structure is this:

id -- category -- parent_id

I use this code in my model:

function all_category_ordered($level = 0, $prefix = '<li>') {
$rows = $this->db
->select('id,category,parent_id')
->where('parent_id', $level)
->order_by('id','asc')
->get('category')
->result();

$category = null;

if (count($rows) > 0) {

foreach ($rows as $row) {
$category .= $prefix . $row->category . "\n";
// Append subcategories
$category .= "</li>".$this->all_category_ordered($row->id, $prefix . '*') ;
}
}
return $category;
}

it works fine and the out put of the code is like this:

<li>menu 1</li>
<li>menu 2</li>
<li>menu 3</li>
<li>*submenu 1</li>
<li>menu 4</li>
<li>*submenu 2</li>

but I want to change the model to out put in ul and li correct order to style it correctly.

preferred order:

<ul>
<li>menu 1</li>
<li>menu 2</li>
<li>menu 3
<ul>
<li>*submenu 1</li>
</ul>
</li>
<li>menu 3
<ul>
<li>*submenu 1</li>
</ul>
</li>
</ul>

Any help would be appreciated.
I would recommend taking the HTML/formatting out of the model as a starting point. If you can create a library/helper with a method/function which simply takes an array and returns a formatted string for output, it should simplify the problem for you. Then your model can retrieve the data from the database and return a multidimensional array, e.g.
Code:
array(
    'menu 1',
    'menu 2',
    'menu 3' => array(
        'submenu 1',
    ),
    'menu 4' => array(
        'submenu 1',
    ),
)
I have a post about that:
http://davicotico.com/menu-multinivel-ph...bootstrap/
It is in Spanish.
Basically:
1.- Create a recursive function in a helper
PHP Code:
function create_menu(array $arrayItem$id_parent 0$level 0){
    echo 
str_repeat("\t" $level ),'<ul>',PHP_EOL;
    foreach( 
$arrayItem[$id_parent] as $id_item => $item){
        echo 
str_repeat("\t" $level ),'<li><a href="',$item['link'],'">',$item['text'],'</a>',PHP_EOL;
        if(isset( 
$arrayItem[$id_item] ) ){
            
create_menu($arrayItem $id_item $level 2);
        }
        echo 
str_repeat("\t" $level ),'</li>',PHP_EOL;
    }
    echo 
str_repeat("\t" $level ),'</ul>',PHP_EOL;

2.- Get the data from the table, put the result to array and call the function
PHP Code:
$sql 'SELECT * FROM _menuitem where id_menu=? and _status=1 ORDER BY parent ASC';
$result $this->db->query($sql, array($id))->result();
$menuItens = array();
foreach (
$result as $row ){
    
$menuItens[$row->parent][$row->id_menuitem] = array('link' => $row->link,'text' => $row->text);
}
create_menu($menuItens);//Call the function 
Full explanation: Here
Simple implementation with adjacency list: https://github.com/michalsn/CodeIgniter-Adjacency-List
this is my class
PHP Code:
<?php

class Multi_categories
{
 
   private $style NULL;
 
   private $code_igniter NULL;

 
   public function __construct()
 
   {
 
       $this->code_igniter = &get_instance();
 
   }

 
   public function setStyle($style NULL)
 
   {
 
      $this->style = ($style != NULL) ? $style '<a class="[active]" href="[link]">[name]</a>';
 
      return;
 
   }
    
 
   public function menu($parent_id 0$data = array())
 
   {
 
       $stop = (( ! isset($data['stop'])) ? TRUE $data['stop']);
 
       $level = (( ! isset($data['level'])) ? $data['level']);
 
       $active = (( ! isset($data['active'])) ? FALSE $data['active']);

 
       $query $this->code_igniter->db->get_where('categories', array('parent_id' => $parent_id));

 
       $menu '';
        
 
       foreach ($query->result() as $current)
 
       {
 
           $sub_level = ($stop === TRUE) ? ($current->parent_id $level) : TRUE;
 
           $is_active = (($active === TRUE) OR ($current->parent_id == 0)) ? 'active' '';
            
 
           $style_data = array(
 
               '[value]' => $current->id,
 
               '[link]' => $current->id,
 
               '[name]' => $current->name,
 
               '[active]' => $is_active,
 
               '[sub_menu]' => NULL,
 
           );
            
            
 
           if(($parent_id == $current->parent_id) && $sub_level)
 
           {
 
               $style_data['[sub_menu]'] = $this->menu($current->id$data);
 
           }
            
 
           $menu .= $this->buildStyle($style_data);
 
       }
 
       return $menu;
 
   }
 
   
    private 
function buildStyle($data = array(), $style NULL)
 
   {
 
       return str_replace(array_keys($data), array_values($data), ($style === NULL) ? $this->style $style);
 
   }


in MY_Controller i have this(it's not needed to be in MY_Controller but i don't want to write the same code in every place)
i have the 'Multi_categories' library autoloaded but you can do $this->load->library('Multi_categories');
PHP Code:
   public function categories_menu($category_id 0) {
 
 // $this->load->library('Multi_categories');
 
       $this->multi_categories->setStyle('<li><a class="list-group-item [active]" href="' base_url() . 'products/[link]">[name]</a><ul class="submenu">[sub_menu]</ul></il>');

 
        return $this->multi_categories->menu($category_id);
 
   
and if i want it i do
PHP Code:
$data['sidebar'] = $this->categories_menu($category); 

and in the view
Code:
<ul>
<?=$sidebar;?>
</ul>
the only problem is it will have an empty
<ul class="submenu"></ul> but it's a easy fix

if you want to get only this main categories you can do

PHP Code:
$this->multi_categories->menu(0, ['stop' => true'level' => 0'active' => false]); 
the default will show only the first level off categories like
main category>sub category
to get all categories do
PHP Code:
$this->multi_categories->menu(0, ['stop' => false]); 
or if you want only a second level or bigger 
like 
main category>
       sub category>
            sub category
do
PHP Code:
$this->multi_categories->menu(0, ['stop' => true'level' => 1]); 
level 1 = mc>sc
level 2 = mc>sc>sc
level 3 = mc>sc>sc>sc
level * = mc>(level * sc)

you can see the defaults here
PHP Code:
$stop = (( ! isset($data['stop'])) ? TRUE $data['stop']);
        
$level = (( ! isset($data['level'])) ? $data['level']);
// this will add the word "active" if you have [active] in the style i use it as a class for the main categories
        
$active = (( ! isset($data['active'])) ? FALSE $data['active']); 
The older version of Community Auth had an example of outputting a category menu where the elements were stored in the database in a parent -> child relationship. The example also accommodates categories where the names may be the same, and is fully and infinitely recursive:

https://bitbucket.org/skunkbad/community...?at=master
hi
Multi level category multiselect CodeIgniter
https://github.com/hamedhossani/Multi_le...odeIgniter