I am assuming this is not the easy way of doing it , but it's my home assignment, so bear with me please.
I have a table in Mysql 'menu'
with the following structure :
id - number
parent_id - number (0 for root)
title - string
link - string
The parent_id links with the id of a certain row , in this case product1
with products
.
example :
1 | 0 | about | about.html
2 | 0 | products | products.html
3 | 2 | product1 | product1.html
4 | 2 | product2 | product2.html
5 | 2 | product3 | product3.html
My goal is to make a set of ul
's that look something like this :
<ul>
<li><a href="about.html"> about </a></li>
<li><a href="products.html"> products </a>
<ul>
<li> <a href="product1.html"> product 1 </a></li>
<li> <a href="product1.html"> product 1 </a></li>
...
</ul>
</li>
...
</ul>
So far I've only made it to be one ul
:
<?php
function getAll() {
DBconnect();
$result = mysql_query("SELECT * FROM `menu`");
$listitems = array();
while ($li = mysql_fetch_array($result)) {
$listitems[] = $li;
}
return $listitems;
}
?>
<ul>
<?php
include_once 'functions.php';
$listitems = getAll();
foreach ($listitems as $listitem) {
?>
<li><a href="<?php print $listitem['link']; ?>"><?php print $listitem['title']; ?></a></li>
<?php } ?>
</ul>
This is where the problem starts , I can't figure out how to make the second function or how to condition it in order for the "submenu" rows to be a ul
in a ul
.
If you don´t have a huge number of elements in the table it´s very easy to solve this. As Syed Qarib user said, you can check if current item has some children´s.
The key is make the paint of html recursive using the parent_id.
This is the code that you need:
<?php
function getElementsByParentId($parent_id) {
DBconnect();
$query = sprintf("SELECT * FROM `menu` WHERE parent_id=%s",
mysql_real_escape_string($parent_id));
$result = mysql_query($query);
<!-- Alternative using concat
$result = mysql_query("SELECT * FROM `menu` WHERE parent_id=".$parent_id);
-->
$listitems = array();
while ($li = mysql_fetch_array($result)) {
$listitems[] = $li;
}
return $listitems;
}
function paintChildrens($parent_id) {
$listitems = getElementsByParentId($parent_id);
if (count($listitems) > 0) {
?>
<ul>
<?php
foreach($listitems as $listitem) {
?>
<li><a href="<?php print $listitem['link']; ?>"><?php print $listitem['title']; ?></a></li>
<?php
paintChildrens($listitem['id']);
}
?>
</ul>
<?php
}
}
include_once 'functions.php';
paintChildrens(null) ?>
I´m not a PHP developer so it´s possible that this code has some errors like null value check.
There are two ways to solve this problem:
1. Choose data from the database recursively (this approach was suggested above). This is bad in terms of load and the number of database queries. But this approach is simpler in terms of code.
2. Select all records from the table and form one query tree on the PHP. Below I give an example of how to do it (PHP version> = 5.4)
<?php
function itemsCmd($a, $b)
{
return strnatcmp($a['path'], $b['path']);
}
function getAll()
{
// fetch all from DB
$itemsRaw = [
['id' => 1, 'parent_id' => 0, 'title' => 'about', 'link' => 'about.html'],
['id' => 2, 'parent_id' => 0, 'title' => 'products', 'link' => 'products.html'],
['id' => 3, 'parent_id' => 2, 'title' => 'product1', 'link' => 'product1.html'],
['id' => 4, 'parent_id' => 2, 'title' => 'product2', 'link' => 'product2.html'],
['id' => 5, 'parent_id' => 3, 'title' => 'product11', 'link' => 'product11.html'],
['id' => 6, 'parent_id' => 4, 'title' => 'product21', 'link' => 'product21.html'],
['id' => 7, 'parent_id' => 4, 'title' => 'product22', 'link' => 'product22.html'],
];
// get path for each item (like /1/2/4) and item level from 0 to N
$items = [];
foreach ($itemsRaw as $key => $item) {
$item['path'] = [$item['id']];
$item['level'] = 0;
$parentId = $item['parent_id'];
while ($parentId) {
foreach ($itemsRaw as $row) {
if ($row['id'] == $parentId) {
$newParentId = $row['parent_id'];
$item['path'][] = $row['id'];
break;
}
}
$parentId = $newParentId;
$item['level']++;
}
$item['path'] = implode('/', array_reverse($item['path']));
$items[] = $item;
}
// order items by path
usort($items, 'itemsCmd');
return $items;
}
?>
<ul>
<? $currentLevel = 0; ?>
<? foreach (getAll() as $index => $item) :?>
<?php if ($currentLevel < $item['level']) : ?>
<ul>
<li>
<?=$item['title']?>
<?php elseif ($currentLevel > $item['level']) : ?>
<? for($i = 0; $i < $currentLevel; $i++) : ?>
</li>
</ul>
<? endfor ?>
<li>
<?=$item['title']?>
<?php else : ?>
<? if ($index) :?>
</li>
<? endif ?>
<li>
<?=$item['title']?>
<?php endif ?>
<? $currentLevel = $item['level']?>
<? endforeach ?>
<? for($i = 0; $i < $currentLevel; $i++) : ?>
</li>
</ul>
<? endfor ?>
Try:
function menu ( $p )
{
$hdr = 0;
foreach ($li in $listitems)
{
if ( $li['parent_id'] == $p )
{
if ( !$hdr ) { $hdr++; echo "<UL>";
echo "<LI>...";
menu( $li['id'] );
}
}
if ( $hdr ) echo "</UL>";
}
Use:
menu( 0 );
in place of your existing html generation code.
This should work with as many sub-menu levels as you like.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.