PHP foreach categories and subcategories - php

I am working with my project that has a capabality in making categories and subcategories. What I've made in my database is that the subcategory column has a relationship to category_key column
Meaning, all records that doesn't have a value in subcategory column is considered as category, the rest are subcategory.
In the picture below:
b is a subcategory of a
e, g, h is a subcategory of d
And now I am using this code to diplay it in my page:
<?php
$query = "SELECT * FROM `categories`";
$result = mysql_query($query);
while($row = mysql_fetch_array($result)){
if(empty($row['subcategory'])){
echo '
<li class="dd-item dd3-item" id="'.$row['category_key'].'" data-name="'.$row['category_name'].'" data-key="'.$row['category_key'].'">
<div class="dd-handle dd3-handle">
<i class="fa fa-bars" aria-hidden="true"></i>
</div>
<div class="dd-edit other-handle edit">
<i class="fa fa-pencil" aria-hidden="true"></i>
</div>
<div class="dd-edit other-handle delete">
<i class="fa fa-trash" aria-hidden="true"></i>
</div>
<div class="dd3-content">'.$row['category_name'].'</div>
</li>
';
}else{
echo '
<ol class="dd-list">
<li class="dd-item dd3-item" id="'.$row['category_key'].'" data-name="'.$row['category_name'].'" data-key="'.$row['category_key'].'">
<div class="dd-handle dd3-handle">
<i class="fa fa-bars" aria-hidden="true"></i>
</div>
<div class="dd-edit other-handle edit">
<i class="fa fa-pencil" aria-hidden="true"></i>
</div>
<div class="dd-edit other-handle delete">
<i class="fa fa-trash" aria-hidden="true"></i>
</div>
<div class="dd3-content">'.$row['category_name'].'</div>
</li>
</ol>
';
}
}
?>
The problem is <ol> element is repeating as it must be only one and also it must be inside the parent <li> of it's category.
Any help?

You need to structure your result array first:
function appendChildren($input)
{
$output = [];
foreach($input as $value)
{
$key = $value["category_key"];
if(empty($input["subcategory"]))
{
$output[$key] = [];
$output[$key]["value"] = $value;
$output[$key]["children"] = [];
} else {
$parent_key = $value["subcategory"];
$output[$parent_key]["children"][] = $value;
}
}
return $output;
}
then you'll have an array like this:
|-- b
|-- a
|
|-- c
|-- d
|-- e
|-- g
|-- h
|
|-- f
Now, begins the formatting:
$input = [];
$query = "SELECT * FROM `categories`";
$result = mysql_query($query);
while($row = mysql_fetch_array($result)){
$input[] = $row;
}
$result = appendChildren($input);
foreach($result as $row)
{
// open <li> tag
if(count($row["children"]) > 0)
{
foreach($children as $child)
// add ordered list
}
// close <li> tag
}

Related

PHP Multi-level menu

I have this code that supposed to generate a multi-level menu from my database. My problem I have a specific HTML code when there are/are no child menu.
Here is the HTML Code if the menu does not have a child menu:
<li class="nav-item dropdown">Menu</li>
Here is the HTML code if the menu has a child menu:
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle arrow-none" href="javascript: void(0);" id="topnav-user-access" role="button">
<span key="t-user-access">Parent Menu</span> <div class="arrow-down"></div>
</a>
<div class="dropdown-menu" aria-labelledby="topnav-user-access">
Child Menu 1
Child Menu 2
...
</div>
</li>
Here is my PHP code to generate the menu.
public function generate_multilevel_menu($module_id, $username, $parent_menu = null){
$menu = '';
if(!empty($parent_menu)){
$query = 'SELECT MENU_ID, MENU, PARENT_MENU, IS_LINK, MENU_LINK FROM technical_menu WHERE MODULE_ID = :module_id AND PARENT_MENU = :parent_menu ORDER BY ORDER_SEQUENCE, MENU';
}
else{
$query = 'SELECT MENU_ID, MENU, PARENT_MENU, IS_LINK, MENU_LINK FROM technical_menu WHERE MODULE_ID = :module_id AND (PARENT_MENU IS NULL OR PARENT_MENU = "0") ORDER BY ORDER_SEQUENCE, MENU';
}
$sql = $this->db_connection->prepare($query);
$sql->bindValue(':module_id', $module_id);
if(!empty($parent_menu)){
$sql->bindValue(':parent_menu', $parent_menu);
}
if($sql->execute()){
while($row = $sql->fetch()){
$menu_id = $row['MENU_ID'];
$menu_access_right = $this->check_role_access_rights($username, $menu_id, 'menu');
if($menu_access_right > 0){
if(!empty($row['MENU_LINK'])){
$menu .= ''. $row['MENU'] .'';
#$menu .= '<li class="nav-item dropdown">'. $row['MENU'] .'</li>';
}
else{
$menu .= '<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle arrow-none" href="javascript: void(0);" id="topnav-user-access" role="button">
<span key="t-user-access">'. $row['MENU'] .'</span> <div class="arrow-down"></div>
</a>';
}
$menu .= '<div class="dropdown-menu" aria-labelledby="topnav-user-access">' . $this->generate_multilevel_menu($module_id, $username, $row['MENU_ID']) . '</div>';
$menu .= '</li>';
}
}
return $menu;
}
}
Here is the screenshot of my database structure and details.
Here is the sample output of my code:
My problem is that I can't seem to incorporate the HTML code to fit my code. The code works if the HTML code is a simple HTML list but using my HTML code and conditions I can't seem to fix it. What part of my code do I need to modify to accommodate my if conditions?

how to set tree view in dynamic menu in codeigniter

Hello guyyz i need help in design,i don't have ideas about design, i have created dynamic menu in codeigniter i want to set that menu in treeview.
First click on parent menu after open child menus, so how to implement it help me
Here is My View Code:
<?php
foreach ($test as $val) {
$array = explode(",", $val->category_id);
}
foreach ($get_cat as $key => $value) {
if (in_array($value->category_id, $array)) {
echo $value->category_name . ' '; //Here My Menu Print
}
}
?>
You need to fetch all category with parent_id=0 then fetch subCategory. Try something like given below.
public function get_categories(){
$this->db->select('*');
$this->db->from('categories');
$this->db->where('parent_id', 0);
//Add here role condition
$parent = $this->db->get();
$categories = $parent->result();
$i=0;
foreach($categories as $p_cat){
$categories[$i]->sub = $this->sub_categories($p_cat->cat_id);
$i++;
}
return $categories;
}
Your subcategory function.
public function sub_categories($id){
$this->db->select('*');
$this->db->from('categories');
$this->db->where('parent_id', $id);
//add here role condition
$child = $this->db->get();
$categories = $child->result();
$i=0;
foreach($categories as $p_cat){
$categories[$i]->sub = $this->sub_categories($p_cat->cat_id);
$i++;
}
return $categories;
}
And your controller.
public function categories(){
$this->load->model('model_categories');
$data = $this->model_categories->get_categories();
print_r($data);
}
Here I got solution of dynamic menu design in CodeIgniter:
<?php
//GET CATEGORY ID FROM USER REGISTARTION
foreach ($test as $val) {
$array = explode(",", $val->category_id);
//CATEGORY ID MATCH WITH CATEGORY NAME FROM CATEGORY TABLE
foreach ($listMenuLevel1 as $key => $value) {
if (in_array($value->category_id, $array)) {
?>
<ul class="sidebar-menu">
<li class="treeview">
<a href="#">
<i class="fa fa-share"></i> <span><?php echo $value->category_name; ?></span>
<i class="fa fa-angle-left pull-right"></i>
</a>
<ul class="treeview-menu">
<?php foreach ($this->main_model->listchildMenus($value->category_id) as $menu2) : ?>
<li class="treeview">
<i class="fa fa-circle-o"></i><?php echo $menu2->category_name; ?><i class="fa fa-angle-left pull-right"></i>
<?php foreach ($this->main_model->listchildMenus($menu2->category_id) as $menu3): ?>
<ul class="treeview-menu">
<li class="treeview">
<i class="fa fa-circle-o"></i><?php echo $menu3->category_name; ?>
</li>
</ul>
<?php endforeach; ?>
</li>
<?php endforeach; ?>
</ul>
</li>
</ul>
<?php } ?>
<?php
}
}
?>

Load data into a html class

I am retrieving data from mysql and need to display the result in a specific class. I am using jquery to update every 10 seconds and this is working ok. Where I am getting stuck is getting that data into a specific class: actions.
I would be grateful if someone could point me in the right direction? php or jquery will be acceptable. Many thanks
$sql= mysqli_query($conn,"SELECT count(*) as total FROM act WHERE new = '1'");
$rows = mysqli_fetch_assoc($sql);
$num = $rows['total'];
$ni = $num;
if($ni < 1) {
$ni = '0';
} else {
echo $ni; <--- NEED TO LOAD RESULT IN ACTIONS CLASS
}
Example html from header.php
<li>
Boxes <span class="drop-icon">▸</span> <label class="drop-icon" for="sm4" title="Toggle Drop-down">▾</label>
<input id="sm4" type="checkbox">
<ul class="sub-menu">
<li>
New Intake <span style="float: right;" class="notification ni"><?php echo $ni_num; ?></span>
</li>
<li>
Retrievals <span style="float: right;" class="notification retrievals"><?php echo $brtv_num; ?></span>
</li>
<li>
Returns <span style="float: right;" class="notification returns"><?php echo $brtn_num; ?></span>
</li>
<li>
Destructions <span style="float: right;" class="notification destructions"><?php echo $bdstr_num; ?></span>
</li>
<li>
Permanent Retrieval <span style="float: right;" class="notification pretrieval"><?php echo $prtv_num; ?></span>
</li>
</ul>
</li>
Example from loadActions.php
$sql= mysqli_query($conn,"SELECT count(*) as total FROM act WHERE new = '1'");
$rows = mysqli_fetch_assoc($sql);
$num = $rows['total'];
$ni = $num;
if($ni < 1) {
$ni = '0';
} echo $ni;
$nisql= mysqli_query($conn,"SELECT count(*) as intake FROM act WHERE activity='New Intake' AND new = '1'"); // provide db connection object as first parameter
$ni_row = mysqli_fetch_assoc($nisql);
$ninum = $ni_row['intake'];
//echo $num;
$ni_num = $ninum;
if($ni_num < 1) {
$ni_num = '0';
} echo $ni_num;
$brtvsql= mysqli_query($conn,"SELECT count(*) as brtv FROM act WHERE activity='Box Retrieval' AND new = '1'"); // provide db connection object as first parameter
$brtv_row = mysqli_fetch_assoc($brtvsql);
$brtvnum = $brtv_row['brtv'];
//echo $num;
$brtv_num = $brtvnum;
if($brtv_num < 1) {
$brtv_num = '0';
} echo $brtv_num;
$brtnsql= mysqli_query($conn,"SELECT count(*) as brtn FROM act WHERE activity='Box Return' AND new = '1'"); // provide db connection object as first parameter
$brtn_row = mysqli_fetch_assoc($brtnsql);
$brtnnum = $brtn_row['brtn'];
//echo $num;
$brtn_num = $brtnnum;
if($brtn_num < 1) {
$brtn_num = '0';
} echo $brtn_num;
Please note, I am NOT a PHP programmer so you will have to do some work yourself
Take below as pseudo code and ask another PHP question if the PHP does not make sense.
Have ONE request
select activity,
count(*) total,
sum(activity = 'New Intake') intakeCount,
sum(activity = 'Box Retrieval') boxCount,
...
from act WHERE new = '1'
if ($rec["total"] == 0) {
echo '{ "total" : 0 }';
die 0;
}
$res = array(
"total" => $rec["total"],
"ni" => $rec["intakeCount"],
"retrievals" => $rec["boxCount"],
...
);
echo json_encode($res);
Result should be
{ "total" : 24,
"ni" : 14,
"retrievals" : 9,
....
}
Then you can do
function getBoxes() {
$.get('/domain/admin/loadActions.php', function(data) {
processData(data);
setTimeout(getBoxes, 15000);
});
}
function processData(data) {
for (key in data) {
console.log(key,data[key])
$("." + key).text(data[key]);
}
}
$(function() { // page load
// testing - remove this when running the getBoxes():
processData({
"total": 24,
"ni": 14,
"retrievals": 9
});
// getBoxes(); // remove comment when tested
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<li>
Boxes <span class="drop-icon">▸</span> <label class="drop-icon" for="sm4" title="Toggle Drop-down">▾</label>
<input id="sm4" type="checkbox">
<ul class="sub-menu">
<li>
New Intake <span style="float: right;" class="notification ni"></span>
</li>
<li>
Retrievals <span style="float: right;" class="notification retrievals"></span>
</li>
<li>
Returns <span style="float: right;" class="notification returns"></span>
</li>
<li>
Destructions <span style="float: right;" class="notification destructions"></span>
</li>
<li>
Permanent Retrieval <span style="float: right;" class="notification pretrieval"></span>
</li>
</ul>
</li>
<div class="total"></div>

Build boostrap4 navmenu from multiple mysql tables

I want to make a bootstrap 4 nav-menu, I have the following SQL query and I have some codes below it but I can't get my head around how to do this!
These are the tables
TABLE menu
--------------------------------------
| id | title | url |
| 1 | Home | index.php |
| 2 | Menu | # |
| 3 | Contact | # |
| 2 | Winkelwagen | winkelwagen.php |
--------------------------------------
TABLE categories
-------------------------------------
| id | title_cat | url | cparent_id |
| 1 | Auto's | # | 2 |
| 2 | Drank | # | 2 |
-------------------------------------
TABLE products
-------------------------------------
| id | product | url | pparent_id |
| 1 | Ferrari | # | 1 |
| 2 | Heineken | # | 2 |
-------------------------------------
Here is the query:
$query = "SELECT
X.level,
X.id,
X.name,
X.url,
X.parent_id
FROM
(
SELECT
1 AS LEVEL,
id AS id,
title AS NAME,
url AS url,
0 AS parent_id,
id AS id_1,
-1 AS id_2,
-1 AS id_3
FROM
menu
WHERE
1
UNION
SELECT
2 AS LEVEL,
id AS id,
title_cat AS NAME,
url AS url,
cparent_id AS parent_id,
cparent_id AS id_1,
id AS id_2,
-1 AS id_3
FROM
categories
WHERE
1
UNION
SELECT
3 AS LEVEL,
products.id AS id,
products.product AS NAME,
products.url AS url,
products.pparent_id AS parent_id,
categories.cparent_id AS id_1,
categories.id AS id_2,
products.id AS id_3
FROM
products
LEFT JOIN categories ON products.pparent_id = categories.id
WHERE
1
) X
WHERE
1
ORDER BY
id_1,
id_2,
id_3";
Which gives the following table with levels (and I added the parent_id too, but with the parent_id buildTree($array) goes into a loop):
level id name url parent_id
1 1 Home index.php 0
1 2 Menu # 0
2 1 Auto's # 2
3 1 Ferrari # 1
2 2 Drank # 2
3 2 Heineken # 2
1 3 Contact contact.php 0
1 4 Winkelwagen winkelwagen.php 0
I want the nav-menu to look like this:
<li class="nav-item">
<a class="nav-link" href="index.php">Home</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Menu</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<div class="dropdown-submenu">
<a class="dropdown-item dropdown-toggle" href="#">Auto's</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="#">Ferrari</a>
</div>
</div>
<div class="dropdown-submenu">
<a class="dropdown-item dropdown-toggle" href="#">Drank</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="#">Heineken</a>
</div>
</div>
</div>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Contact</a>
</li>
<li class="nav-item">
<a class="nav-link" href="winkelwagen.php">Winkelwagen</a>
</li>
I have the following codes, first we make a array from the query fetched which you already saw above:
$sql = $pdo->prepare($query);
function menu_builder($sql) {
if ($sql->execute()) {
while ($row = $sql->fetch(PDO::FETCH_ASSOC)) {
$array[] = $row;
}
buildTree($array); // or menu_builder($sql);
}
}
The next code doesn't work because it goes into a infinite loop (and if it works I still need to make the html right :):
function buildTree($array, $parent_id = 0, $parents = array()) {
if($parent_id == 0) {
foreach ($array as $element) {
if (($element['parent_id'] != 0) && !in_array($element['parent_id'], $parents)) {
$parents[] = $element['parent_id'];
}
}
}
$menu_html = '';
foreach($array as $element) {
if($element['parent_id'] == $parent_id) {
if(in_array($element['id'], $parents)) {
$menu_html .= '<li class="dropdown">';
$menu_html .= ''.$element['name'].' <span class="caret"></span>';
}
else {
$menu_html .= '<li>';
$menu_html .= '' . $element['name'] . '';
}
if(in_array($element['id'], $parents)) {
$menu_html .= '<ul class="dropdown-menu" role="menu">';
$menu_html .= buildTree($array, $element['id'], $parents);
$menu_html .= '</ul>';
}
$menu_html .= '</li>';
}
}
return $menu_html;
}
And this one makes a normal <ul>/<li> menu which I don't know how to get it working for me with bootstrap:
function menu_builder($sql) {
$level = 0;
if ($sql->execute()) {
while ($row = $sql->fetch(PDO::FETCH_ASSOC)) {
while($level < $row['level']) {
echo "<ul>" . PHP_EOL;
$level++;
}
while($level > $row['level']) {
echo "</ul>" . PHP_EOL;
$level--;
}
echo " <li>#" . $row['id'] . "->" . $row['name'] . "</li>" . PHP_EOL;
}
}
while($level-- > 0) {
echo "</ul>" . PHP_EOL;
}
}
If you need more information please ask me, I tried to make the question as clear as possible with the codes I'm trying and the table I'm using.
jQuery:
$('.dropdown-menu a.dropdown-toggle').on('click', function(e) {
if (!$(this).next().hasClass('show')) {
$(this).parents('.dropdown-menu').first().find('.show').removeClass("show");
}
var $subMenu = $(this).next(".dropdown-menu");
$subMenu.toggleClass('show');
$(this).parents('li.nav-item.dropdown.show').on('hidden.bs.dropdown', function(e) {
$('.dropdown-submenu .show').removeClass("show");
});
return false;
});
CSS:
.dropdown-submenu {
position: relative;
}
.dropdown-submenu a::after {
transform: rotate(-90deg);
position: absolute;
right: 6px;
top: .8em;
}
.dropdown-submenu .dropdown-menu {
top: 0;
left: 100%;
margin-left: .1rem;
margin-right: .1rem;
}
I've gone for a more linear approach than your recursive buildTree. It's a little easier this way because of the need to output different HTML dependent on the level of the tree. I've created an SQLFiddle for your data with a few extra values I added for testing purposes. The query changes so that I can see whether a menu item has a submenu and also if that submenu has a product, all in one row:
SELECT m.title AS title, m.url AS m_url,
c.title_cat AS title_cat, c.url AS c_url,
p.product AS product, p.url AS p_url
FROM menu m
LEFT JOIN categories c
ON c.cparent_id = m.id
LEFT JOIN products p
ON p.pparent_id = c.id
ORDER BY m.id, c.id, p.id
The output of this query (based on the expanded data) is:
title m_url title_cat c_url product p_url
Home index.php (null) (null) (null) (null)
Menu # Auto's # Ferrari www.ferrari.com
Menu # Auto's # Maserati #
Menu # Drank # Heineken #
Menu # Food # (null) (null)
Second Menu # Hotels # The Ritz www.ritzparis.com
Contact contact.php (null) (null) (null) (null)
Winkelwagen winkelwagen.php (null) (null) (null) (null)
The basic query call remains the same although instead of fetching all the data and then processing it, I fetch the data and process it at the same time.
$sql = $pdo->prepare($query);
$sql->execute() or die("Unable to execute query!");
buildTree($sql);
The buildTree routine. I think it's fairly self-explanatory with the comments but basically it goes through each row of data and determines if it needs to create a new menu item, a new submenu, or a new submenu item in turn.
function buildTree($sql) {
$thisTitle = '';
$thisCategory = '';
while ($element = $sql->fetch(PDO::FETCH_ASSOC)) {
if (!$element['c_url']) {
// simple top element
// do we need to close any prior menus?
if ($thisCategory != '') {
echo " </div>\n </div>\n";
$thisCategory = '';
}
if ($thisTitle != '') {
echo "</li>\n";
$thisTitle = '';
}
echo <<<EOD
<li class="nav-item">
<a class="nav-link" href="{$element['m_url']}">{$element['title']}</a>
</li>
EOD;
}
else {
// got a category
// do we need a new menu item?
if ($element['title'] != $thisTitle) {
// is it the first menu item? if not, need to close the previous one
if ($thisTitle != '') {
// do we also need to close a previous category menu?
if ($thisCategory != '') {
echo " </div>\n </div>\n";
$thisCategory = '';
}
echo "</li>\n";
}
$thisTitle = $element['title'];
echo <<<EOD
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="{$element['m_url']}" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">$thisTitle</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
EOD;
}
// do we need a new submenu?
if ($element['title_cat'] != $thisCategory) {
// is it the first submenu? if not, need to close the previous one
if ($thisCategory != '') echo " </div>\n";
$thisCategory = $element['title_cat'];
// create a submenu
echo <<<EOD
<div class="dropdown-submenu">
<a class="dropdown-item dropdown-toggle" href="{$element['c_url']}">$thisCategory</a>
EOD;
}
// is there a product?
if ($element['p_url']) {
// create a product menu item
echo <<<EOD
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="{$element['p_url']}">{$element['product']}</a>
</div>
EOD;
}
}
}
}
The output of this code for the extended data is:
<li class="nav-item">
<a class="nav-link" href="index.php">Home</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Menu</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<div class="dropdown-submenu">
<a class="dropdown-item dropdown-toggle" href="#">Auto's</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="www.ferrari.com">Ferrari</a>
</div>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="#">Maserati</a>
</div>
</div>
<div class="dropdown-submenu">
<a class="dropdown-item dropdown-toggle" href="#">Drank</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="#">Heineken</a>
</div>
</div>
<div class="dropdown-submenu">
<a class="dropdown-item dropdown-toggle" href="#">Food</a>
</div>
</div>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Second Menu</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<div class="dropdown-submenu">
<a class="dropdown-item dropdown-toggle" href="#">Hotels</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="www.ritzparis.com">The Ritz Paris</a>
</div>
</div>
</div>
</li>
<li class="nav-item">
<a class="nav-link" href="contact.php">Contact</a>
</li>
<li class="nav-item">
<a class="nav-link" href="winkelwagen.php">Winkelwagen</a>
</li>
I think part of what is making this difficult is trying to combine creating your data structures with presentation. Usually it is best to structure your data first before worrying about how to present it.
I tried my best to break this up into separate steps as best I could. I added some commented out print_r statements so you can see what each step is doing. Let me know if you have any questions about it.
#!/usr/bin/php
<?php
// The query results
$results = [
// Level, id, title, link, parent
[1, 1, 'Home', 'index.php', 0],
[1, 2, 'Menu', '#', 0],
[2, 1, "Auto's", '#', 2],
[3, 1, 'Ferrari', '#', 1],
[2, 2, 'Drank', '#', 2],
[3, 2, 'Heineken', '#', 2],
[1, 3, 'Contact', 'contact.php', 0],
[1, 4, 'Winkelwagen', 'winkelwagen.php', 0],
];
// creates a constant for the query result row keys (you should avoid using a global constant for this)
define('KEYS', ['level', 'id', 'title', 'link', 'parent_id']);
// adds the keys to each result row (this is just to help readability/maintainability)
$rows = array_map(function (array $item): stdClass {
// cast this as an object so we don't have to use pass by reference later (I think this improves readability).
return (object)array_combine(KEYS, $item);
}, $results);
// uncomment to see raw $rows
//print_r($rows);die;
// creates a key for each row based on the level and id (this way they will be unique)
$keys = array_map(function (stdClass $row): string {
$key = "$row->level-$row->id";
$row->key = $key;
return $key;
}, $rows);
$keyed = array_combine($keys, $rows);
// uncomment to see $keyed values
//print_r($keyed);die;
// converts the keyed records into a tree.
$tree = [];
foreach($keyed as $item) {
if (1 === $item->level) {
$tree[] = $item;
continue;
}
$parent = ($item->level - 1).'-'.$item->parent_id;
if (!isset($keyed[$parent])) {
throw new Exception("could not find parent element '$parent'");
}
$keyed[$parent]->children[] = $item;
}
// uncomment to see $tree structure
//print_r($tree);die;
?>
<!-- add ul classes for style -->
<ul>
<?php foreach ($tree as $trunk): ?>
<?php if (!isset($trunk->children)): ?>
<li class="nav-item">
<a class="nav-link" href="<?=$trunk->link?>"><?=$trunk->title?></a>
</li>
<?php else: ?>
<li class="nav-item dropdown">
<!-- id attributes must be unique so we add the item key to the end of it to make it unique-->
<a class="nav-link dropdown-toggle" role="button"
href="<?=$trunk->link?>" id="navbarDropdown<?=$trunk->key?>"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><?=$trunk->title?></a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<?php foreach ($trunk->children as $branch): ?>
<?php if (!isset($branch->children)): ?>
<!-- add style to this if needed -->
<?=$branch->title?>
<?php else: ?>
<div class="dropdown-submenu">
<a class="dropdown-item dropdown-toggle" id="navbarDropdown<?=$branch->key?>"
href="<?=$branch->link?>"><?=$branch->title?></a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown<?=$branch->key?>">
<!-- You may need to add some additional style code to this for it to work with multiple items -->
<?php foreach ($branch->children as $leaf): ?>
<a class="dropdown-item" href="<?=$branch->link?>"><?=$branch->title?></a>
<?php endforeach; ?>
</div>
</div>
<?php endif ?>
<?php endforeach; ?>
</div>
</li>
<?php endif ?>
<?php endforeach ?>
</ul>
As a rule of thumb I try to avoid using nested loops, but in this instance each level seemed to have separate styling. If you ever want to make this able to handle more then three levels you may want to think about using a recursive function.
Try This
<?php
$servername = "localhost";
$username = "root";
$password = "";
try {
$pdo = new PDO("mysql:host=$servername;dbname=testing", $username, $password);
// set the PDO error mode to exception
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
echo "Connection failed: " . $e->getMessage();
}
$querySubmenu = "SELECT a.id, a.title, a.url, b.title_cat AS cat_name, b.url AS cat_url, c.product AS product_name, c.url AS product_url FROM menu a
JOIN (SELECT * FROM categories) b ON a.id = b.cparent_id
JOIN (SELECT * FROM products) c ON b.id = c.pparent_id";
$queryMenu = "SELECT a.*, 0 AS cat_name, 0 AS cat_url, 0 AS product_name, 0 AS product_url FROM menu a WHERE id NOT IN (
SELECT a.id FROM menu a
JOIN (SELECT * FROM categories) b ON a.id = b.cparent_id
JOIN (SELECT * FROM products) c ON b.id = c.pparent_id)";
$sqlMenu = $pdo->prepare($queryMenu);
$sqlSubmenu = $pdo->prepare($querySubmenu);
$menu = menu_builder($sqlMenu);
$submenu = menu_builder($sqlSubmenu);
$arr = array_merge($menu, $submenu);
usort($arr, function ($a, $b) {
return $a['id'] - $b['id'];
});
function menu_builder($sql)
{
if ($sql->execute()) {
while ($row = $sql->fetch(PDO::FETCH_ASSOC)) {
$array[] = $row;
}
return $array;
}
}
foreach ($arr as $element) {
if ($element['cat_name'] == '0') { ?>
<li class="nav-item">
<a class="nav-link" href="<?php echo $element['url'] ?>"><?php echo $element['title'] ?></a>
</li>
<?php }
if ($element['cat_name'] != '0') { ?>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><?php echo $element['title'] ?></a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<div class="dropdown-submenu">
<a class="dropdown-item dropdown-toggle" href="<?php echo $element['cat_url'] ?>"><?php echo $element['cat_name'] ?></a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="<?php echo $element['product_url'] ?>"><?php echo $element['product_name'] ?></a>
</div>
</div>
</div>
</li>
<?php }
}
?>

Undefined property in Foreach

I'm logging into my system and once I login, the idea is that the menu is updated according to the type of user profile, for which I'm doing from the database and showing the menu through a Foreach. However within the Foreach, when comparing one of the rows with a number, that is, with an id I get this error message and other similar ones:
Message: Undefined property: mysqli::$id_man
So I think that I'm not recognizing the value of the row, why is it happening, how could I correct it?
Controller
public function ingresar(){
$nombre_usu= $this->input->post('nombre_usu');
$pass_usu= $this->input->post('pass_usu');
$res= $this->M_Login->ingresar($nombre_usu,$pass_usu);
if ($res ==1) {
$this->load->view('layouts/Header.php');
// if the user exists, show the menu according to his profile
$data['menu_barra'] = $this->M_Login->show_menu();
$this->load->view('layouts/Menu.php', $data);
$this->load->view('usuarios/V_Index.php');
$this->load->view('layouts/Footer.php');
} else {
$data['mensaje'] = "Usuario o contraseña Incorrecta";
$this->load->view('V_Login',$data);
}
}
Model
public function show_menu(){
$id_tip= $this->session->userdata('tipo');
$this->db->select('id_mc, id_tip, id_man');
$this->db->from('mantenedores_cuenta');
$this->db->where('id_tip',$id_tip);
$menu = $this->db->get();
$horarios ="";
$informes="";
foreach ($menu as $row) {
if ($row->id_man == 1 ) {
$horarios .='<li class="active"><i class="fa fa-circle-o"></i>Administrar Horarios</li>';
}
if ($row->id_man == 2 ) {
$horarios .='<li><i class="fa fa-circle-o"></i>Agendar Citas</li>';
}
if ($row->id_man == 3 ) {
$horarios .='<li><i class="fa fa-circle-o"></i>Consultar Citas</li>';
}
if ($row->id_man == 4 ) {
$informes .='<li class="active"><i class="fa fa-circle-o"></i>Porcentaje de Citas</li>';
}
} //Fin del Foreach
$menu_barra="
<ul class='sidebar-menu'>
<li class='header'>MENU</li>
<li class='active treeview'>
<a href='#'>
<i class='fa fa-fw fa-calendar'></i> <span>Horarios</span>
<span class='pull-right-container'>
<i class='fa fa-angle-left pull-right'></i>
</span>
</a>
<ul class='treeview-menu'>
'$horarios'
</ul>
</li>
<li class='treeview'>
<a href='#'>
<span class='glyphicon glyphicon-stats'></span><span>Informes</span> <i class='fa fa-angle-left pull-right'></i>
</a>
<ul class='treeview-menu'>
'$informes'
</ul>
</li>
<li><a href='documentation/index.html'><i class='fa fa-book'></i> <span>Documentación</span></a></li>
<li><a href='documentation/index.html'><i class='fa fa-fw fa-sign-out'></i><span>Salir</span></a></li>
</ul> ";
return ($menu_barra);
}
View (menu)
<aside class="main-sidebar">
<section class="sidebar">
<div class="user-panel">
<div class="pull-left image">
<img src="<?php echo base_url();?>assets/dist/img/user2-160x160.jpg" class="img-circle" alt="User Image">
</div>
<div class="pull-left info">
<p><?php echo $this->session->userdata('s_usuario');?></p>
<i class="fa fa-circle text-success"></i><?php echo $this->session->userdata('cuenta');?>
</div>
</div>
// show the menu according to your profile
<?php echo $menu_barra; ?>
</section>
<!-- /.sidebar -->
I also tried to show it in this way, but I was not allowed in an array or at least that was what the message said, example: $row["id_man"] == 3
Change
foreach ($menu as $row) {
to
foreach ($menu->result() as $row) {
See here for documentation
You could also use
foreach ($menu->result_array() as $row) {
and access properties like
$row['id_man'];
Ensure that your table mantenedores_cuenta has the following column: id_man

Categories