CodeIgniter 创建 n 级深度导航
我想要一些帮助.我创建了一个动态菜单导航栏,根据我设置的顺序显示菜单项.我正在使用这个 nestedsortable 插件来订购我的菜单项,但目前我的菜单只有 2 个级别,所以基本上是这样的:
Item1项目 2>分项2.1>分项2.2项目 3等等等等
我想做的是用 n 级来制作它,所以基本上是这样的:
Item1项目 2>分项2.1>>分项2.1.1>分项2.2项目 3等等等等
并且每个项目都可以深入 n 级.问题是,如果我为菜单项设置了一个深度超过 2 级的新订单,我会收到错误消息,并且订单未存储在数据库中.请问这个怎么解决???
数据库结构是这样的:
表格:菜单身份证 (pk)菜单项parent_id//是父菜单项的id命令
这是我的主要(模型)函数:
//保存菜单项的顺序公共函数 save_order($items){如果(计数($项目)> 0){foreach ($items as $order => $item) {如果 ($item['item_id'] != '') {$数据=数组('parent_id' =>(int)$item['parent_id'],'订单' =>$订单);$this->db->set($data)->where($this->_primary_key, $item['item_id'])->更新($this->_table_name);}}}}//从最后一个订单集中获取菜单项(父母和孩子)公共函数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 = 数组();foreach ($menu_items 作为 $item) {//该项没有父项如果 (!$item['parent_id']) {$arr[$item['id']] = $item;//例如$arr(4 => array())}//该项目是一个孩子别的 {//例如$arr(4 => array('children' => array()))$arr[$item['parent_id']]['children'][] = $item;}}返回 $arr;}
更新
如需更多帮助:我进行了测试并在两种情况下都将项目数组转储到屏幕上:
第一种情况:有 2 个级别(目前是这样):我以此顺序设置项目
- 项目 1
- 项目 2
- 项目 4
- Item3
- Item5
结果如下,正如预期的那样:
数组([1] =>大批([id] =>1[menu_item] =>项目 1[parent_id] =>0)[2] =>大批([id] =>2[menu_item] =>项目 2[parent_id] =>0[儿童] =>大批([0] =>大批([id] =>4[menu_item] =>项目 4[parent_id] =>2)))[3] =>大批([id] =>3[menu_item] =>项目 3[parent_id] =>0)[5] =>大批([id] =>5[menu_item] =>第5项[parent_id] =>0))
第二种情况: n 级:我尝试按以下顺序设置菜单项:
- 项目 1
- 项目 2
- Item5
- 项目 4
- Item5
- Item3
结果如下:
数组([1] =>大批([id] =>1[menu_item] =>项目 1[parent_id] =>0)[2] =>大批([id] =>2[menu_item] =>项目 2[parent_id] =>0[儿童] =>大批([0] =>大批([id] =>5[menu_item] =>第5项[parent_id] =>2)))[3] =>大批([id] =>3[menu_item] =>项目 3[parent_id] =>0)[4] =>大批([儿童] =>大批([0] =>大批([id] =>4[menu_item] =>项目 4[parent_id] =>4))))
在这种情况下,我收到错误并且无法工作.我得到的错误是:
消息:未定义索引:page_id消息:未定义索引:menu_item
在我的视图文件中:
function nav($menu_items, $child = false){$输出 = '';如果(计数($数组)){$output .= ($child === false) ?'<ol class="sortable">': '';foreach ($menu_items 作为 $item) {$output .= '<li id="list_' . $item['id'] . '">';//这是第一个错误的行$output .=''.$item['menu_item'] .'</div>';//第二个错误//检查是否有孩子if (isset($item['children']) && count($item['children'])) {$output .= nav($item['children'], true);}$output .='';}$output .= '</ol>';}返回 $output;}回声导航($menu_items);
解决方案 考虑到数据库输出,似乎项目正确存储在数据库中.问题属于get_menu()
方法及其创建输出的算法.
为了创建n级深层菜单,您应该递归地遍历项目.
我们开始:
function prepareList(array $items, $pid = 0){$输出=数组();# 遍历项目foreach ($items as $item) {# item的parent_id是否匹配当前的$pidif ((int) $item['parent_id'] == $pid) {# 递归调用函数,使用item的id作为父id# 函数返回子列表或空数组()if ($children = prepareList($items, $item['id'])) {# 存储当前项的所有子项$item['children'] = $children;}# 填充输出$output[] = $item;}}返回 $output;}
您可以将上述逻辑用作helper 函数(在 CodeIgniter 中)或 Controller 类中的私有方法.
然后在 get_menu()
方法中调用该函数/方法,如下所示:
公共函数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();返回prepareList($menu_items);}
注意:我使用了 prepareList()
作为辅助(全局)函数.如果您决定将其用作私有方法,则应在任何地方(甚至在函数内部)用 $this->prepareList()
替换函数名称.
这是在线演示.
I'd like some help please. I have created dynamic a menu navbar that displays the menu items accoridning to the order that I've set them. I'm using this nestedsortable plugin, to order my menu items, but currently my menu has only 2 levels, so basicly it goes like this:
Item1
Item2
> Subitem2.1
> Subitem2.2
Item3
etc etc.
What I'd like to do is make it with n-levels, so basicly something like this:
Item1
Item2
> Subitem2.1
>> Subitem2.1.1
> Subitem2.2
Item3
etc etc.
and each item can go n-level deep. The problem is that if I set a new order to my menu items that is more than 2 levels deep I get an error and the order is not stored in the database. How can I fix this please ???
The database structure is this:
table: Menu
id (pk)
menu_item
parent_id // it is the id of the parent menu item
order
Here are my main (model) functions:
// 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;
}
Update
For additional help: I did a test and dumped the array of the items on the screen in both cases:
1st case: with 2 levels (as it is currently): I set the items with this order
- Item1
- Item2
- Item4
- Item3
- Item5
and the result looks like this, as expected:
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
)
)
2nd case: with n-levels: I tried to set the menu items with this order:
- Item1
- Item2
- Item5
- Item4
- Item5
- Item3
and the result looks like this:
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
)
)
)
)
This is the case where I get the error and not working. The errors I get are:
Message: Undefined index: page_id Message: Undefined index: menu_item
in my view file:
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);
解决方案
Considering the database output, it seems the items are stored in the database correctly. And the problem belongs to the get_menu()
method and its algorithm to create the output.
In order to create a n-level deep menu, you should iterate through the items recursively.
Here we go:
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;
}
You could use the above logic as a helper function (in CodeIgniter) or a private method within your Controller class.
Then call that function/method inside get_menu()
method as follows:
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);
}
Note: I used the prepareList()
as a helper (global) function. If you decide to use that as a private method, you should replace the function name by $this->prepareList()
everywhere (even inside the function itself).
Here is the Online Demo.
相关文章