Materialize dropdown issue - php

I'm trying to make dynamic dropdown menu. I have database table with dropdown menus.
Table layout
position means position in menu. dropdown (0 - no dropdown, 1 - dropdown "header" with that arrow, 2 - dropdown item). dropdown-parent means id of dropdown header.
Problem is that I can't figure out how to implement it.
$query = $db->query("SELECT * FROM `menu` WHERE
`dropdown` = 0 OR `dropdown` = 1 ORDER BY `position` ASC");
foreach($query as $row) {
if($row['dropdown'] == 0) {
echo '<li>'.$row['name'].'</li>';
}
elseif($row['dropdown'] == 1) {
echo '<li><a class="dropdown-button" href="#" data-activates="dropdown'.$row['position'].'" data-beloworigin="true" data-hover="true">'.$row['name'].'<i class="material-icons right">arrow_drop_down</i></a></li>';
}
}
This code works, but for dropdown items I need to edit this
<ul id="dropdown2" class="dropdown-content">
<li>Test #1</li>
</ul>
Do you have any idea how to implement it?
EDIT
This is what I want
<ul id="dropdown1" class="dropdown-content">
<li>Test item #1 for dropdown1</li>
<li>Test item #2 for dropdown1</li>
<li>Test item #x for dropdown1</li>
</ul>
<ul id="dropdown2" class="dropdown-content">
<li>Test item #1 for dropdown2</li>
<li>Test item #2 for dropdown2</li>
</ul>
<ul id="dropdownx" class="dropdown-content">
<li>Test item for dropdownx</li>
</ul>
<ul class="right hide-on-med-and-down">
<li>Header without dropdown</li>
<li><a class="dropdown-button" href="#" data-activates="dropdown1">Header with dropdown1 items</a></li>
<li><a class="dropdown-button" href="#" data-activates="dropdown2">Header with dropdown2 items</a></li>
<li><a class="dropdown-button" href="#" data-activates="dropdownx">Header with dropdownx items</a></li>
</ul>
I tried this
$query = $db->query("SELECT * FROM `menu` WHERE `dropdown` = 2 ORDER BY position ASC");
foreach($query as $row) {
echo '<ul id="dropdown'.$row['dropdown-parent'].'" class="dropdown-content">
<li>'.$row['name'].'</li>
</ul>';
}
but I'll get
<ul id="dropdown1" class="dropdown-content">
<li>Test item #1 for dropdown1</li>
</ul>
<ul id="dropdown1" class="dropdown-content">
<li>Test item #2 for dropdown1</li>
</ul>
<ul id="dropdown1" class="dropdown-content">
<li>Test item #x for dropdown1</li>
</ul>
<ul id="dropdown2" class="dropdown-content">
<li>Test item #1 for dropdown2</li>
</ul>
<ul id="dropdown2" class="dropdown-content">
<li>Test item #2 for dropdown2</li>
</ul>
<ul id="dropdownx" class="dropdown-content">
<li>Test item #1 for dropdownx</li>
</ul>
There's problem in that foreach, but I don't know hot to fix it.

You need to make the <ul> based on some logic. There are three steps. You are on the first one, you need to end one and create another, you are on the last one. Below is an untested attempt. Should get you close. Also a note I changed $query to $rows for clarity.
$rows = $db->query("SELECT * FROM `menu` WHERE `dropdown` = 2 ORDER BY position ASC");
$start = true; // Just to know we are starting
foreach($rows as $row) {
if($start){ // Need to only create an open ul tag
echo '<ul id="dropdown'.$row['dropdown-parent'].'" class="dropdown-content">';
$start = false; // Never do this again.
}
if(isset($lastRowParent) && $lastRowParent != $row['dropdown-parent']){
echo '</ul>'; //End the last dropdown
// Start the next one
echo '<ul id="dropdown'.$row['dropdown-parent'].'" class="dropdown-content">';
}
echo '<li>'.$row['name'].'</li>'; //Output the content
$lastRowParent = $row['dropdown-parent']; // Update the parent
}
echo '</ul>'; //When the loop ends the last ul will not be closed. close it.

you can use switch case in place of else if.
$query = $db->query("SELECT * FROM `menu` WHERE `dropdown` = 0 OR `dropdown` = 1 ORDER BY `position` ASC");
foreach($query as $row) {
SWITCH($row['dropdown']) {
CASE 0:
echo '<li>'.$row['name'].'</li>';
break;
CASE 1 :
echo '<li><a class="dropdown-button" href="#" data-activates="dropdown'.$row['position'].'" data-beloworigin="true" data-hover="true">'.$row['name'].'<i class="material-icons right">arrow_drop_down</i></a></li>';
break;
}
}

Related

Categories are repeating for each subcategory

I am showing categories in Menu. Some categories have subcategories.
function for getting parent categories
function get_parent_category(){
$query="select * from blog_categories where parent_id=0
ORDER BY
CASE id
WHEN '2' THEN 1
WHEN '1' THEN 2
WHEN '3' THEN 3
ELSE id
END";
$rows=array();
$result=$this->query($query);
while($row=$this->fetch_array($result)){
$row['url']=$this->get_cat_url($row);
$rows[]=$row;
}
return $rows;
}
Function for subcategories
function get_child_category(){
$query="select * from blog_categories where parent_id!=0";
$rows=array();
$result=$this->query($query);
while($row=$this->fetch_array($result)){
$row['url']=$this->get_cat_url($row);
$rows[]=$row;
}
return $rows;
}
Showing on the page like this:
<ul class="nav navbar-nav">
<li>Home</li>
<?php
foreach($this->parent_category as $cat){
foreach($this->child_category as $child_cat){
if($cat['id']==$child_cat['parent_id']){
?>
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#"><?php echo $cat['name'];?>
<span class="caret"></span></a>
<ul class="dropdown-menu">
<li><?php echo $child_cat['name']?></li>
</ul>
</li>
<?php
}elseif($cat['parent_id']==0){
?>
<li><span><?php echo $cat['name'];?></span></li>
<?php
}
?>
<?php }}?>
Output and Problem
The Main category circle in red color is seerah which has two subcategories. showing two times for first one in drop down one subcategory and for second time second subcategory is showing.
DB structure
What i wants:
I wants to show each subcategories under each parent category without repetition , how can i achieve this?
Here is how i handled the problem
<?php
foreach($this->parent_category as $cat){
$html = '';
foreach($this->child_category as $child_cat){
if($cat['id']==$child_cat['parent_id']){
$html .= '<li>' . $child_cat['name'] . '</li>';
// here is all child categories are saved in var.
}
}
if ($html == '') {
?>
<li><span><?php echo $cat['name'];?></span></li>
<?php
} else {
?>
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#"><?php echo $cat['name'];?>
<span class="caret"></span></a>
<ul class="dropdown-menu">
<?php echo $html; ?> // here is displayed under parent category
</ul>
</li>
<?php
}
}
?>
Output
To me it seem you did not split your html and loops properly here:
foreach($this->parent_category as $cat){
foreach($this->child_category as $child_cat){
if($cat['id']==$child_cat['parent_id']){
?>
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#"><?php echo $cat['name'];?>
<span class="caret"></span></a>
<ul class="dropdown-menu">
<li><?php echo $child_cat['name']?></li>
</ul>
</li>
Usually whenever you have a loop you should have some output before any nested loop started. In your case first level loop is about Categories which should become an <li> of parent main menu <ul>.
I think. You need to transform this fragment to:
foreach($this->parent_category as $cat){ ?>
<li ...>
...
<ul ...> <?php
foreach($this->child_category as $child_cat){ ?>
<li>...</li> <?php
} ?>
</ul>
</li> <?php
}
when you do not have repetitive value in $rows, why you use this part again for $cat['name']?
elseif($cat['parent_id']==0){
?>
<li><span><?php echo $cat['name'];?></span></li>
<?php
}
when in first part of foreach you create
<a class="dropdown-toggle" data-toggle="dropdown" href="#"><?php echo $cat['name'];?>

how to pass value from while loop to next page after clicking on menu item php

I have a a navigation bar and one of the nav items is a dropdown with sub categories. Only the subcategories are being pulled from the database by using a while loop.
When clicking on one of the dropdown items they will be redirected to dancerProfile.php.
I want dancerProfile.php to pull the menu item name from the other pages.
html
<li class="li-spacing">Home</li>
<li class="dropdown li-spacing">
<a class="dropdown-toggle" data-toggle="dropdown">Dancers<b class="caret"></b></a>
<ul class="dropdown-menu">
<?php
$dancers = "SELECT `dancer_name` FROM `dancers` WHERE name = '$name'";
$dres = mysqli_query($con,$dancers);
//if($res==FALSE){
//die('there was an error running query [' . $con->error . ']');
// }
while($data=mysqli_fetch_array($dres)){
$dancerName = $data['dancer_name'];
foreach ($dancerName as $DANCER){
echo '
<li>'.$data["dancer_name"].'</li>
<li class="divider"><hr></li>
';
}
}
?>
<li>Add New</li>
</ul>
</li>
This works well as all dancers appear in the dropdown.
What I want is that when I click on dancerA the dancerProfile.php will show dancerA information. And when I click on dancerB it will show dancerB info, etc.
But it will only show the last dancer's information no matter which name I click on.
dancerProfile.php
<div class="col-sm-6 dancerInfo">
<div class="row">
<div class="col-sm-6">
<div class="dancerName"><?php echo $dancerName;?></div>
</div>
So When I click on dancerA on the nav bar in any other page, in dancerProfile.php $dancerName should print dancerA. And it should print dancerB if I clicked on dancerB from the nav bar.
but it is only printing dancerB no matter which link I click.
I am using bootstrap. Can anyone help me?
EDIT
Here's an update of what my code looks like now.
<li class="li-spacing">Home</li>
<li class="dropdown li-spacing">
<a class="dropdown-toggle" data-toggle="dropdown">Dancers<b class="caret"></b></a>
<ul class="dropdown-menu">
<?php
$dancers = "SELECT `dancer_name`, `id` FROM `dancers` WHERE name = '$name'";
$dres = mysqli_query($con,$dancers);
$dancerId= 'id';
}
while($data=mysqli_fetch_array($dres)){
$dancerName = $data['dancer_name'];
echo '
<li>'.$data["dancer_name"].'</li>
<li class="divider"><hr></li>
';
}
?>
<li>Add New</li>
</ul>
</li>
And dancerProfile.php:
<?PHP
if(isset($_GET['id'])) {
$dancerId=$_GET['id'];
$dancerquery = "SELECT `dancer_name` FROM `dancers` WHERE id = " . $_GET['id'] . ";";
$dancer_res = mysqli_query($con,$dancers);
if($dancer_res){
$DANCER='dancer_name';
}
}
?>
<div class="col-sm-6 dancerInfo">
<div class="row">
<div class="col-sm-6">
<div class="dancerName"><?php echo " $DANCER ";?></div>
</div>
I also forgot to mention that this navigation is also on dancerProfile page. So all of the code I am providing is on dancerProfile page. I don't know if that matters
My database table
You need pass dancer id or which is unique in your dancer table. something like given below.
<li>'.$data["dancer_name"].'</li>
And now go to dancerProfile.php and try something like this.
if (isset($_GET['dancer_id'])) {
$dancer_id=$_GET['dancer_id'];
//your query
}
Your full code:
<li class="li-spacing">Home</li>
<li class="dropdown li-spacing">
<a class="dropdown-toggle" data-toggle="dropdown">Dancers<b class="caret"></b></a>
<ul class="dropdown-menu">
<?php
$dancers = "SELECT `dancer_name`, `id` FROM `dancers` WHERE name = '$name'";
$dres = mysqli_query($con,$dancers);
$dancerId= 'id';
}
while($data=mysqli_fetch_array($dres)){ ?>
$dancerName = $data['dancer_name'];
<li><?php echo $data['dancer_name']; ?>'</li>
<li class="divider"><hr></li>
<?php } ?>
<li>Add New</li>
</ul>
</li>
Your dancerProfile.php should be
<?PHP
if(isset($_GET['id'])) {
$dancerId=$_GET['id'];
$dancerquery = "SELECT `dancer_name` FROM `dancers` WHERE id = '$dancerId'";
$dancer_res = mysqli_query($con,$dancerquery);
$data=mysqli_fetch_array($dancer_res);
}
?>
<div class="col-sm-6 dancerInfo">
<div class="row">
<div class="col-sm-6">
<div class="dancerName"><?php echo $data['dancer_name'];?></div>
</div>
You are currently overriding the value of $DANCER with each iteration, so the last will always be the used value.
Just change your loop a bit:
while($data=mysqli_fetch_array($dres)){
echo '<li>'.$data['dancer_name'].'</li>';
}

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 }
}
?>

Dynamically insert class="active" into php function that generates bootstrap menu

I have tried pretty much every solution that was available online but cannot get the class="active" to change dynamically for each menu section.
When someone clicks the top level menu item it opens up the second level menu and if someone click the on a second level menu item in that section class="active" needs to remain on the top level menu li tag.
I have the following function that generates my bootstrap menu:
function getMenu() {
global $connection;
mysqli_select_db($connection, "c9");
$query = ("SELECT testName, testId FROM testType");
$result_set = mysqli_query($connection, $query);
while ($row = mysqli_fetch_array($result_set)) {
$testId = $row['testId'];
$testName = $row['testName'];
echo '<li>'; //This is where class="active" needs to be added
echo '<span class="nav-label">'.$testName.'</span>';
echo '<ul class="nav nav-second-level collapse">';
echo '<li>Summary Report</li>';
echo '<li>Add Data</li>';
echo '</ul>';
echo '</li>';
}
}
And the menu structure is as follows:
<ul class="nav metismenu" id="side-menu">
<li class="active">
<a href="/">
<span class="nav-label">Summary</span>
<ul class="nav nav-second-level collapse in">
<li>Reports</li>
</ul>
</li>
<li><a href="#">
<span class="nav-label">Temperature</span>
<ul class="nav nav-second-level collapse">
<li>Summary Report</li>
<li>Add Data</li>
</ul>

Show a hierarchy in PHP

I have a database which stores a hierarchy of foods.
Category(id_cat,name_cat);
his_low_cat(id_cat,id_low_cat);
A category can have 0..n low category. If it had no lower category I do a id_cat,-1 field in his_low_cat.
I do not know if it's possible but I would like to show it in a kind of "pulldown menu"
(if you have any other idea on how to show a full hierarchy please suggest it)
Like this :
echo " <div id=\"menu\">
<ul class=\"niveau1\">
<li class=\"sousmenu\">Food
<ul class=\"niveau2\">
<li class=\"sousmenu\">Sous menu 1.1
<ul class=\"niveau3\">
<li>Sous sous menu 1.1.1</li>
</ul>
</li>
<li>Sous menu 1.2</li>
</ul>
</li>
</ul>
</div>";
My first cat is "food" and then it derives into 4 lowers categories, which derive themselves in more.
The problem is that it must be dynamic and load field from my database.
The goal would be to be able to catch the clicked value and use it in another .php
How would I do this?
Recursion is definitely the way to go with this problem, I've coded up this solution:
<?php
function nestElements($elements, $depth=0)
{
foreach($elements as $elementName=>$element)
{
echo str_repeat("\t", $depth).'<ul class="niveau'.($depth+1).'">'."\n";
if(is_array($element))
{
echo str_repeat("\t", $depth+1)."<li class=\"sousmenu\">${elementName}\n";
nestElements($element, $depth+2);
echo str_repeat("\t", $depth+1)."</li>\n";
}
else
{
echo str_repeat("\t", $depth+1)."<li class=\"sousmenu\">${elementName}</li>\n";
}
echo str_repeat("\t", $depth)."</ul>\n";
}
}
nestElements(array("Food"=>array("Meat"=>array("Poultry"=>array("Chicken"=>"Meat/Poultry/Chicken"), "Beef"=>array("Hamburgers"=>"Meat/Beef/Hamburgers", "Steak"=>"Meat/Beef/Steak")), "Dairy"=>array("Cow"=>"Dairy/Cow", "Sheep"=>"Dairy/Sheep")), "name"=>"url"));
?>
Testing with this:
<?php
nestElements(array("Food"=>array("Meat"=>array("Poultry"=>array("Chicken"=>"Meat/Poultry/Chicken"), "Beef"=>array("Hamburgers"=>"Meat/Beef/Hamburgers", "Steak"=>"Meat/Beef/Steak")), "Dairy"=>array("Cow"=>"Dairy/Cow", "Sheep"=>"Dairy/Sheep")), "name"=>"url"));
?>
Results in:
<ul class="niveau1">
<li class="sousmenu">Food</li>
<ul class="niveau2">
<li class="sousmenu">Meat</li>
<ul class="niveau3">
<li class="sousmenu">Poultry</li>
<ul class="niveau4">
<li class="sousmenu">Chicken</li>
</ul>
</ul>
<ul class="niveau3">
<li class="sousmenu">Beef</li>
<ul class="niveau4">
<li class="sousmenu">Hamburgers</li>
</ul>
<ul class="niveau4">
<li class="sousmenu">Steak</li>
</ul>
</ul>
</ul>
<ul class="niveau2">
<li class="sousmenu">Dairy</li>
<ul class="niveau3">
<li class="sousmenu">Cow</li>
</ul>
<ul class="niveau3">
<li class="sousmenu">Sheep</li>
</ul>
</ul>
</ul>
<ul class="niveau1">
<li class="sousmenu">name</li>
</ul>
To parse it you'd have to make a mod_rewrite which redirects to index.php?r=TheURL and from their, explode the r parameter using "/" as the delimeter, then you have a list of menus and submenus that the clicked link was from. By adding another parameter the url coul be automatically generated.
Edit: Fixed problem with original code output seen below
<li class="sousmenu">Sheep</li>
<li class="sousmenu">Sheep</li>
To generate the array:
<?php
function genArray(&$targetArray, $parentID=null){
$res=(is_null($parentID))?mysql_query("SELECT * FROM categorie WHERE id_cat NOT IN (SELECT id_low_cat FROM hislowcat) ORDER BY id_cat DESC;"):mysql_query("SELECT *, (SELECT name_cat FROM categorie WHERE id_cat= '".$parentID ."') AS name_cat FROM hislowcat WHERE id_cat= '" .$parentID ."'");
if(!is_null($parentID) && !mysql_num_rows($res))
{
$res3=mysql_query("SELECT name_cat FROM categorie WHERE id_cat='${parentID}';");
$row3=mysql_fetch_array($res3);
$targetArray[$row3['name_cat']]=$row3['name_cat'];
return;
}
while(($row=mysql_fetch_array($res)))
{
//echo $row->name_cat;
if(is_null($parentID))
{
if(!isset($targetArray[$row['name_cat']]))
{
$targetArray[$row['name_cat']]=array();
}
genArray($targetArray[$row['name_cat']], $row['id_cat']);
}
else
{
genArray($targetArray[$row['name_cat']], $row['id_low_cat']);
}
}
}
$array=array();
genArray($array);
print_r($array);
?>
Notice how $targetArray is set up as a reference, this way we can treat it one-dimensionally.

Categories