I imagine you're looking at something like the following:
Model
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;
}
}
Controller
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);
}
}
View
<!-- 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; ?>
The Fix
In trying to think of the most "headache free" way to handle this, I decided you'd need to make a few small changes throughout the process.
First of all, you'll need to make some small changes to expected array. Not sure if that model is used in other places (i imagine it is), so we won't change the model. Instead, we'll start at changing the data in the controller. This way, you can pass a new array, with 3 levels of data, to the view.
Controller
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);
}
Now you should have a new level to work with in your view!
<?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; ?>
I'm working back and forth between a bunch of my own real work and this, so just comment if something didn't quite turn out right, and i'll try to fix it! Good luck!