CodeIgniter创建n级深度导航

ltd*_*dev 6 php navigation nested codeigniter jquery-ui-sortable

我想请一些帮助.我创建了一个动态菜单导航栏,显示符合我设置顺序的菜单项.我正在使用这个nestedsortable插件,来订购我的菜单项,但目前我的菜单只有2个级别,所以基本上它是这样的:

Item1
Item2
 > Subitem2.1
 > Subitem2.2
Item3
etc etc.
Run Code Online (Sandbox Code Playgroud)

我想做的是用n级制作它,所以基本上是这样的:

Item1
Item2
  > Subitem2.1
    >> Subitem2.1.1
  > Subitem2.2
Item3
etc etc.
Run Code Online (Sandbox Code Playgroud)

并且每个项目都可以达到n级深度.问题是,如果我将新订单设置为超过2级深度的菜单项,则会出现错误,订单不会存储在数据库中.我该怎么办呢?

数据库结构是这样的:

table: Menu
id (pk)
menu_item
parent_id // it is the id of the parent menu item
order
Run Code Online (Sandbox Code Playgroud)

这是我的主要(模型)功能:

// save the order of the menu items
public function save_order($items){
    if (count($items)>0) {
        foreach ($items as $order => $item) {
            if ($item['item_id'] != '') {

                $data = array(
                    'parent_id' => (int)$item['parent_id'], 
                    'order'     => $order
                );

                $this->db->set($data)
                ->where($this->_primary_key, $item['item_id'])
                ->update($this->_table_name);
            }
        }
    }
}

// fetch the menu items (parents & children) from the last order set
public function get_menu(){

    $this->db->select('id, menu_item, parent_id');
    $this->db->order_by('parent_id, order');
    $menu_items = $this->db->get('menu')->result_array();

    $arr = array();
    foreach ($menu_items as $item) {

        // the item has no parent
        if (!$item['parent_id']) {
            $arr[$item['id']] = $item; // e.g. $arr(4 => array())
        } // the item is a child
        else {
            // e.g. $arr(4 => array('children' => array()))
            $arr[$item['parent_id']]['children'][] = $item;
        }
    }
    return $arr;
 } 
Run Code Online (Sandbox Code Playgroud)

更新

如需其他帮助:在两种情况下,我都进行了测试并将屏幕上的项目数组转储:

第一种情况:有2个级别(因为它是当前的):我使用此订单设置项目

  • 项目1
  • 项目2
    • 项目4
  • 项目3
  • 项目5

结果看起来像预期的那样:

Array
(
    [1] => Array
        (
            [id] => 1
            [menu_item] => Item1
            [parent_id] => 0
        )

    [2] => Array
        (
            [id] => 2
            [menu_item] => Item2
            [parent_id] => 0
            [children] => Array
                (
                    [0] => Array
                        (
                            [id] => 4
                            [menu_item] => Item4
                            [parent_id] => 2
                        )

                )

        )

    [3] => Array
        (
            [id] => 3
            [menu_item] => Item3
            [parent_id] => 0
        )

    [5] => Array
        (
            [id] => 5
            [menu_item] => Item5
            [parent_id] => 0
        )

)
Run Code Online (Sandbox Code Playgroud)

第二种情况:使用n级:我尝试使用此顺序设置菜单项:

  • 项目1
  • 项目2
    • 项目5
      • 项目4
  • 项目3

结果如下:

Array
(
    [1] => Array
        (
            [id] => 1
            [menu_item] => Item1 
            [parent_id] => 0
        )

    [2] => Array
        (
            [id] => 2
            [menu_item] => Item2
            [parent_id] => 0
            [children] => Array
                (
                    [0] => Array
                        (
                            [id] => 5
                            [menu_item] => Item5
                            [parent_id] => 2
                        )

                )

        )

    [3] => Array
        (
            [id] => 3
            [menu_item] => Item3
            [parent_id] => 0
        )

    [4] => Array
        (
            [children] => Array
                (
                    [0] => Array
                        (
                            [id] => 4
                            [menu_item] => Item4
                            [parent_id] => 4
                        )

                )

        )

)
Run Code Online (Sandbox Code Playgroud)

这是我得到错误而不工作的情况.我得到的错误是:

消息:未定义的索引:page_id消息:未定义的索引:menu_item

在我的视图文件中:

function nav($menu_items, $child = false){
    $output = '';

    if (count($array)) {
        $output .= ($child === false) ? '<ol class="sortable">' : '<ol>' ;

        foreach ($menu_items as $item) {
            $output .= '<li id="list_' . $item['id'] . '">'; // here is the line of the 1st error
            $output .= '<div>' . $item['menu_item'] . '</div>'; // 2nd error

            //check if there are any children
            if (isset($item['children']) && count($item['children'])) {
                $output .= nav($item['children'], true);
            }
            $output .= '</li>';
        }
        $output .= '</ol>';
    }
    return $output;
}


echo nav($menu_items); 
Run Code Online (Sandbox Code Playgroud)

Has*_*ami 2

考虑到数据库输出,这些项目似乎已正确存储在数据库中。问题属于get_menu()创建输出的方法及其算法。

为了创建n 级深层菜单,您应该递归地迭代这些项目。

开始了:

function prepareList(array $items, $pid = 0)
{
    $output = array();

    # loop through the items
    foreach ($items as $item) {

        # Whether the parent_id of the item matches the current $pid
        if ((int) $item['parent_id'] == $pid) {

            # Call the function recursively, use the item's id as the parent's id
            # The function returns the list of children or an empty array()
            if ($children = prepareList($items, $item['id'])) {

                # Store all children of the current item
                $item['children'] = $children;
            }

            # Fill the output
            $output[] = $item;
        }
    }

    return $output;
}
Run Code Online (Sandbox Code Playgroud)

您可以将上述逻辑用作辅助函数(在 CodeIgniter 中)或Controller 类中的私有方法。

然后在方法内调用该函数/方法,get_menu()如下所示:

public function get_menu()
{
    $this->db->select('id, menu_item, parent_id');
    $this->db->order_by('parent_id, order');
    $menu_items = $this->db->get('menu')->result_array();

    return prepareList($menu_items);
}
Run Code Online (Sandbox Code Playgroud)

注意:我使用prepareList()作为辅助(全局)函数。$this->prepareList()如果您决定将其用作私有方法,则应该在任何地方(甚至在函数本身内部)替换函数名称。

这是在线演示