【问题标题】:CodeIgniter - Array for 3 level menuCodeIgniter - 3 级菜单的数组
【发布时间】:2016-08-04 15:16:56
【问题描述】:

我的主要开发人员不在,所以我正在扩展我的能力,因为我不是程序员,有能力但不是很好,所以请耐心等待。

我们有一个 2 级菜单生成器。它需要第三级。框架是 CI。

数据库表是“pages_nav” 字段 = navid(唯一)|页码 |父母身份 |入口类型 |目标 |顺序

与名为“页面”的表相关 - 我加入 pages_nav 和 pages 以获取 URL 和标题

Entry_type 为 1、2 或 3(顶级、子项或菜单分隔符(菜单项之间的水平规则/中断)

数据库查找是:

$menu = $this->db
      ->select('P.id, P.title, P.url, N.entry_type, N.target, N.order, N.parentid, N.navid')
      ->join('pages P', 'P.id = N.pageid', 'left')
      ->order_by('N.parentid, N.order')
      ->get('pages_nav N')
      ->result_array();

然后我从中得到一个数组(全部在模型中),如果父或子是这样的,则循环并传回:

if(!$menu) return [];
    $menu_out = [];
    foreach($menu as $item) {
      if($item['parentid'] == 0) {
        $menu_out[$item['id']] = ['details'=>$item, 'children'=>[] ];
      } else {
        $menu_out[$item['parentid']]['children'][] = $item;
      }
    }
    return $menu_out;

在控制器中,我只是调用模型并将 $data['menu_items'] 作为 $data 传递给视图。

在视图中,我在 foreach 中有一个 foreach,可以打印出父母和任何孩子,如下所示:

<?php if(!empty($menu_items)): ?>
    <?php foreach($menu_items as $item): ?>
        [ PRINT OUT ROWS: title, URL, Order etc]
        <?php if(count($item['children'])): ?>
            <?php foreach($item['children'] as $child): ?>
                [ PRINT OUT ROWS of child items: title, URL, Order etc]
            <?php endforeach; ?>
        <?php endif; ?>
    <?php endforeach; ?>
<?php else: ?>
    [ no entries found text ]
<?php endif; ?>

我不想更改数据库,除非必要时添加一列。我不想完全重新构建代码,我不需要超过 3 级的递归(100% 确定)所以我需要的是对我必须允许的内容进行无压力、简单的编辑第三级,但无论我尝试什么,我都失败了,所以我正在寻找一些方向。

我一直在寻找的是将 entry_type = 4 用于 3 级作为标识符,但我正在苦苦挣扎......

编辑 -- 现在添加我的 View 以提供帮助:

<?php if(!empty($menu_items)): ?>
    <?php foreach($menu_items as $item): ?>
            <?php
            if($item['details']['target']==0)
                $link_target = "Current";
            else
                $link_target = "New";
            ?>
            <tr class="parent">
                <td><span class="anchor" data-id="<?php echo $item['details']['id']; ?>"><i class="fa fa-chevron-down <?php echo count($item['children']) ? '' : 'off'; ?>"></i> <?php echo $item['details']['title']; ?></span></td>
                <td><?php echo $item['details']['url']; ?></td>
                <td><?php echo $item['details']['order']; ?></td>
                <td><?php echo $link_target; ?> Tab</td>
            </tr>
            <?php if(count($item['children'])): ?>
                <?php foreach($item['children'] as $child): ?>
                    <?php
                    if($child['target']==0)
                        $link_target = "Current";
                    else
                        $link_target = "New";
                    ?>
                    <tr class="child">
                        <?php if($child['entry_type'] == 3): ?>
                            <td colspan>-- DIVIDER --</td>                                  
                        <?php else: ?>
                            <td><?php echo $child['title']; ?></td>
                        <?php endif; ?>
                        <td><?php echo $child['url']; ?></td>
                        <td><?php echo $child['order']; ?></td>
                        <td><?php echo $link_target; ?> Tab</td>
                    </tr>
                <?php endforeach; ?>
            <?php endif; ?>
    <?php endforeach; ?>
<?php else: ?>
    <tr>
        <td colspan="6">No navigation entries</td>
    </tr>
<?php endif; ?>

这是数据库中的条目。最后一个是第 3 级项,与上面的两行(第 2 级)相关,与在上面的行(父级/顶层)相关。

所以有 3 个顶级项目,其中最后一个有 3 个子项(1 个是分隔线),其中一个子项有一个子子项(或子项本身)。

【问题讨论】:

  • 我想,更改将从您的第二个代码示例(菜单循环)开始。就目前而言,它只创建了 2 个级别。第一级基于查找所有父 ID = 0 的位置。这将创建您的“主菜单”。级别 2 是该项目的子项。现在,快速提问,也许我误解了您在下面输入的内容,但是您要添加的第三级到底是什么?它是另一个 DB 值,还是来自 php 中与子级或父级相关的其他内容?仅供参考,我
  • 好的,例如它会是这样的前端菜单: 关于我们 > 公司 > 我们的历史 目前 parentid 与 pageid 相关。 entry_type 只是为了帮助前端了解我们正在显示的内容。虽然我提到了前端,但目前所有这些都只是后端(菜单构建器),因为它基本上显示相同。
  • 部分问题在于对模型 if else 的作用的理解只有一半。我觉得在 else 我应该只是说 if entry_type=4 然后以某种方式将孩子和子孩子 else 只是孩子传回,并且在视图中捕捉到这一点,但它正在融化我的非程序员大脑。
  • 我将开始回答并以此为基础。由于您不是全职程序员,因此我将首先尝试将其分解,以便确保我们在同一页面上...确保检查每个代码部分中的 cmets,如那就是我将尝试解释我的认为我所看到的
  • 谢谢 - 我可能应该注意我还没有确定存储它的方法,所以如果你有基于此的答案,我愿意接受建议。就目前而言,我认为 pageid 的 parentid 与二级相同,但由 entry_type 2(子)或 4(子子)标识。

标签: php arrays codeigniter


【解决方案1】:

我想您正在查看类似以下内容:

型号

class Db_lookup extends CI_Model {
    function __construct() { parent::__construct(); }
    function callDBMenuItems() {
        //  this is simply your call to the database
        //  it retrieves *rows* (array entries) of items that will be like:
        //      index (0 based) [ 'id', 'title', 'url', 'entry_type', 'target', 'order', 'parentid', 'navid' ]
        $menu = $this->db
            ->select('P.id, P.title, P.url, N.entry_type, N.target, N.order, N.parentid, N.navid')
            ->join('pages P', 'P.id = N.pageid', 'left')
            ->order_by('N.parentid, N.order')
            ->get('pages_nav N')
            ->result_array();
    }
    function getMenuItems() {
        $menu = $this->callDBMenuItems();
        if(!$menu) return [];
        //  menu items were found, create an array to put results in
        $menu_out = [];
        foreach($menu as $item) {   //  loops through array
            //  check if adding first entry
            //  by the looks, I assume all top level (1st level)
            //  items have a parent id of '0'
            //  i'm guessing this is to signify they dont have a parent
            if($item['parentid'] == 0) {
                //  add entry to menu_out array, with 2 values
                //  'details' will contain the entire item
                //  'children' looks like it is preped for the else statement
                $menu_out[$item['id']] = ['details'=>$item, 'children'=>[] ];
            } 
            else {
                //  here, it appears we're adding sublevel (level 2) values
                //  level 2 items obviously have a parent id that is not 0
                //  and relates to the item id of an item that 
                //  had a parent id of 0 (aka, this item's parent)
                //  again, but to different calue, this everty's 
                //  value of 'children'.
                //  will gain an array entry of the entire item
                //  this will create and array of children all containing entire items
                $menu_out[$item['parentid']]['children'][] = $item;
            }
        }
        //  our final results, if items found, would in turn look something like:
        /*
            array $menu_out => [
                'id0' => [
                    'details' => [ 'id', 'title', 'url', 'entry_type', 'target', 'order', 'parentid', 'navid' ],
                    'children' => [
                        [0] => [ 'id', 'title', 'url', 'entry_type', 'target', 'order', 'parentid', 'navid' ],
                        [1] => [ 'id', 'title', 'url', 'entry_type', 'target', 'order', 'parentid', 'navid' ]
                    ]
                ],
                'id1' => [
                    'details' => [ 'id', 'title', 'url', 'entry_type', 'target', 'order', 'parentid', 'navid' ],
                    'children' => [
                        [0] => [ 'id', 'title', 'url', 'entry_type', 'target', 'order', 'parentid', 'navid' ],
                        [1] => [ 'id', 'title', 'url', 'entry_type', 'target', 'order', 'parentid', 'navid' ]
                    ]
                ]
            ]
        */
        return $menu_out;
    }
}

控制器

class Page extends CI_Controller {
    function index() {
        //  simmply loads the previously created model,
        // however, you might not see this if your programmer 
        //  was smart enough to add it to the auto-load feature of CI
        $this->load->model('Db_lookup');
        
        /*  this is the array used to pass php items to the view
            each item can be called in the view by using it's
            associative name
            for example, if the array has an entry like [ 'bob' => 'bill' ],
            then in the view, you can get 'bob' simply by calling:
            <?php echo $bob; ?>
            just think of each entry as a declaration of a PHP variable, 
            without the $ sign. You then simply add the $ sign to that item's name
            in the view in order to get that item.  */
        $data = [];
        //  here we add an item to our array that will be passed to the view
        //  note how the entry is 'named'. This is the value we'll 
        //  use to call it in the view
        $data['menu_items'] = $this->Db_lookup->getMenuItems();
        //  load the 'view' (aka, the page you see in the browser)
        //  and pass our data array to it
        $this->load->view('pageName', $data);
    }
}

查看

<!--    as noted before, you can call items from the data array passed through
    simply by adding $ sign to the begining of the item's index name.   -->
<?php if(!empty($menu_items)): ?>
    <ul>
    <!--    since we know `menu_items` is an array, as previously defined in our model,
            then we know we can loop for it based on the creation of it in our model    -->
    <?php foreach($menu_items as $item): ?>
        <!--    [ PRINT OUT ROWS: title, URL, Order etc]    -->
        <?php if(count($item['children'])): ?>
            <!--    I don't see where you've created actual HTML yet, 
                but I assume you're looking for something like: -->
            <li id="order_<?php echo $item['order']; ?>">
                <a href="<?php echo $item['url']; ?>"><?php echo $item['title']; ?></a>
                <ul>
                <?php foreach($item['children'] as $child): ?>
                    <!--    [ PRINT OUT ROWS of child items: title, URL, Order etc] -->
                    <!--    Again, I don't see any HTML you've created, 
                        but this may be something like: -->
                    <li id="order_<?php echo $child['order']; ?>">
                        <a href="<?php echo $child['url']; ?>"><?php echo $child['title']; ?></a>
                    </li>
                <?php endforeach; ?>
                </ul>
            </li>
        <?php endif; ?>
    <?php endforeach; ?>
    </ul>
<?php else: ?>
    <!--    [ no entries found text ]   -->
    <p>Sorry, No Menu Found</p>
<?php endif; ?>

修复

在尝试想出最“不费吹灰之力”的方法来处理这个问题时,我决定您需要在整个过程中进行一些小改动。

首先,您需要对预期的数组进行一些小改动。不确定该模型是否在其他地方使用(我想是),所以我们不会更改模型。相反,我们将从更改控制器中的数据开始。这样,您可以将一个包含 3 级数据的新数组传递给视图。

控制器

function index() {
    $this->load->model('Db_lookup');
    
    //  first let's get the uncut menu_items
    $menu_items = $this->Db_lookup->getMenuItems();
    //  now let's break them down and build a new
    //  array to pass to the view.
    //  this could be done even more easy by changing
    //  the model, however, it's unknown (to me at least)
    //  if that model is used in other places.
    //  it likely is, so let's just modify here instead.
    //  first i'll setup 3 simple arrays. This isn't
    //  the only way to do this, and could be made more
    //  condensed, but for sake of less headache,
    //  i'm breaking it into a visually easy to see array
    //  of the items we want.
    $parent_items = [];
    //  let's make this a little easier, 
    //  if you look back to the array returned from the model,
    //  you'll notice each item should already have and index ID,
    //  so I'll use that in the foreach loop
    foreach ($menu_items as $id => $item) {
        //  at this point, the following 'if' should always be true
        if(isset($item['details']) && $item['details']['parentid'] == 0) {
            //  setup array with easily referable id
            //  mimicking original setup
            $parent_items[$id] = [
                'details' => $item['details'],
                'children' => []    //  empty children, since we want to change how children is handled
                //  by adding a level 3 component
            ];
            //  first, let's get this parent's child items,
            //  but we only want the one's that don't have
            //  `entry_type=4`
            if (!empty($item['children'])) {
                //  let's make this easier to follow
                $uncutChildren = $item['children'];
                //  and make an easy child array to work with,
                //  that will later add back to parent
                $newChildren = [];
                
                //  first let's add the level 2 (children) only
                //  using an $i loop may not have been best approach,
                //  so instead, I'll make a retlational ID,
                //  based on info within the child item
                foreach ($uncutChildren as $child) {
                    //  $child should look like:
                    //  [ 'id', 'title', 'url', 'entry_type', 'target', 'order', 'parentid', 'navid' ]
                    
                    //  if i'm reading the output of the view you posted correctly,
                    //  entry_type 3 is always between your expected children,
                    //  so I assume, every child between 3's should be a level 2,
                    //  OR a level 3 of the previously pulled 2,
                    $childID = count($newChildren);
                    //   with that in mind, try this
                    switch ($child['entry_type']) {
                        case 2:
                        case 3: // adds new entry
                            $newChildren[$childID] = $child;
                            break;
                        case 4:
                            if (!empty($newChildren[$childID-1])) $newChildren[$childID-1]['level3'] = $child;
                            break;
                    }
                }
                
                //  now add in our new children
                $parent_items[$id]['children'] = $newChildren;
            }
        }
    }
    // this should help make a new array that looks like:
    /*
        array $menu_out => [
            'id0' => [
                'details' => [ 'id', 'title', 'url', 'entry_type', 'target', 'order', 'parentid', 'navid' ],
                'children' => [
                    [0] => [ 'id', 'title', 'url', 'entry_type', 'target', 'order', 'parentid', 'navid',
                        'level3' => [ 'id', 'title', 'url', 'entry_type', 'target', 'order', 'parentid', 'navid' ]
                    ]
                ]
            ]
        ]
    */
    $data = [ 'menu_items' => $parent_items ];
    $this->load->view('pageName', $data);
}

现在您的视图中应该有一个可以使用的新关卡了!

<?php if(!empty($menu_items)): ?>
    <?php foreach($menu_items as $item): ?>
            <?php $link_target = $item['details']['target']==0 ? "Current" : "New"; ?>
            <tr class="parent">
                <td>
                    <span class="anchor" data-id="<?php echo $item['details']['id']; ?>">
                        <i class="fa fa-chevron-down <?php echo count($item['children']) ? '' : 'off'; ?>"></i> <?php echo $item['details']['title']; ?>
                    </span>
                </td>
                <td><?php echo $item['details']['url']; ?></td>
                <td><?php echo $item['details']['order']; ?></td>
                <td><?php echo $link_target; ?> Tab</td>
            </tr>
            <?php if(count($item['children'])): ?>
                <?php foreach($item['children'] as $child): ?>
                    <?php $link_target = $child['target']==0 ? "Current" : "New"; ?>
            <tr class="child">
                <?php if($child['entry_type'] == 3): ?>
                    <td colspan>-- DIVIDER --</td>                                
                <?php else: ?>
                    <td><?php echo $child['title']; ?></td>
                <?php endif; ?>
                <td><?php echo $child['url']; ?></td>
                <td><?php echo $child['order']; ?></td>
                <td><?php echo $link_target; ?> Tab</td>
            </tr>
            <!--    ¡¡¡NEW LEVEL!!! -->
            <!--    Not really sure where you want it, so I just created a new row,
                    with a colored background so you can "see" the change   -->
                    <? php if (!empty($child['level3'])): ?>
                        <?php foreach($child['level3'] as $lvl3): ?>
                        <?php $link_target = $lvl3['target']==0 ? "Current" : "New"; ?>
            <tr style="background: yellow;">
                <td><?php echo $lvl3['title']; ?></td>
                <td><?php echo $lvl3['url']; ?></td>
                <td><?php echo $lvl3['order']; ?></td>
                <td><?php echo $link_target; ?> Tab</td>
            </tr>
                        <?php endforeach; ?>
                    <?php endif; ?>
                <?php endforeach; ?>
            <?php endif; ?>
    <?php endforeach; ?>
<?php else: ?>
    <tr>
        <td colspan="6">No navigation entries</td>
    </tr>
<?php endif; ?>

我在一堆我自己的实际工作和这个之间来回工作,所以如果有什么不完全正确的,请发表评论,我会尝试修复它!祝你好运!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-11
    • 2016-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多