print recursive list in php - php

I am trying to print a recursive list where every date has a sublist of events ordered by date.
For example on the database I have:
+------+----------+--------+
| date | event_id | post_id|
+------+----------+--------+
|date1 | event1 | post1 |
|date1 | event2 | post2 |
|date1 | event3 | post3 |
|date2 | event4 | post4 |
|date2 | event5 | post5 |
+------+----------+--------+
I need to print
<ul>
<li>date1</li>
<ul>
<li>event1, post1</li>
<li>event2, post2</li>
<li>event3, post3</li>
</ul>
<li>Date 2</li>
<ul>
<li>event4, post4</li>
<li>event5, post5</li>
</ul>
</ul>
how can I print in php the
select date, event_id, post_id from tablename
query in php to have this?

After a while with php and mysql, I do the least I can in mysql, even if it's often more elegant. Performance of mysql is crap. And even if what you query is fast, it can still slow down another query elsewhere done by another user. So here is a response with the least load on the DB. One query, no grouping. just select your 3 fields, and you can apply this.
$lastDate = null; // lastDate will be updated at each row, so we can check if it has changed the next one.
echo '<ul>';
foreach ($queryResult as $row)
{
if ( $lastDate != $row['date'] )
{
if ( $lastDate) { echo '</ul>'; } // if lastdate "exists", it's not the first, so let't close the "date" list...
echo '<li>', $row['date'], '</li><ul>'; // ... and start a new one
}
echo '<li>', $row['event_id'], ', ',$row['post_id'], '</li>';
$lastDate = $row['date'];
}
echo '</ul>'; // close the very last date list
echo '</ul>'; // close the the full list

It looks like you need MySQL GROUP_CONCAT().
SELECT date,
GROUP_CONCAT(event_id) AS 'event_ids',
GROUP_CONCAT(post_id) AS 'post_ids'
FROM tablename
GROUP BY date
This will return results with three fields. date will be the date field, event_ids and post_ids will be comma separated lists of the events and posts that fall under that date.

This should work. You'd want to add some error checking though.
<ul>
<?php
$result = mysql_query(SELECT date FROM tableName);
if (mysql_num_rows($result) > 0)
{
while ($dateRow = mysql_fetch_array($result))
{
echo "<li>" . $dateRow['date'] . "</li>";
$result2 = mysql_query("SELECT event_id,post_id FROM tableName where date = '" . $dateRow['date'] . "'");
if (mysql_num_row($result2) > 0)
{
echo "<ul>";
while ($row = mysql_fetch_array($result2))
{
echo "<li>" . $row['event_id'] . " , " . $row['post_id'] . "</li>";
}
echo "</ul>";
}
}
}
?>
</ul>

The following is a rough answer:
$query = "select date, event_id, post_id from tablename order by date";
$result = mysql_query($query);
$currentDate = null;
echo "<ul>";
while($row = mysql_fetch_assoc($result)){
if($currentDate != $row['date']){
echo "<li>" . $currentDate . "</li>";
echo "<ul>";
}
echo "<li>" . $row['event'] . $row['post'] . "</li>";
if($currentDate != $row['date']){
$currentDate = $row['date'];
echo "</ul>";
}
}
echo "</ul>";

Here's my take on the problem. First of all, you should nest the unordered list items into parent elements. The resulting output should be
<ul>
<li>date1
<ul>
<li>event1, post1</li>
<li>event2, post2</li>
<li>event3, post3</li>
</ul>
</li>
<li>Date 2
<ul>
<li>event4, post4</li>
<li>event5, post5</li>
</ul>
</li>
</ul>
Advantages of this nested schema:
valid html (this alone is good enough)
easier DOM-manipulation by Javascript
Here's a function which in theory should output the former html:
function printList()
{
$sql = 'SELECT t.event_id, t.post_id, t.date FROM table t ORDER BY date';
$result = mysql_query($sql);
$date = null;
$out = '';
while($row = mysql_fetch_assoc($result))
{
if($date !== $row['date'])
{
if(!is_null($date))
{
$out .= '</ul></li>';
}
$date = $row['date'];
$out .= sprintf('<li>%s<ul>', $row['date']);
}
$out.= sprintf('<li>%s, %s</li>', $row['event_id'], $row['post_id']);
}
return sprintf('<ul>%s</ul></li></ul>', $out);
}

$sql = "SELECT date, event_id, post_id
FROM tablename
GROUP BY date ORDER BY date";

Related

Datebase and php parent id

Hello i'm working on this all day today and i'm actually really lost i have a table like this at the moment.
id | category | parent_id
id=5 category=Laptop parent_id=0
id=7 category=Houses parent_id=0
id=8 category=HP parent_id=5
id=9 category=Lenovo parent_id=5
so what i'm trying to do is get this as a category sub category style something like;
Laptop
HP
Lenovo
Houses
until know what i have;
<?php
include_once("dir/db.php");
$result = $db->query("SELECT * FROM categories WHERE parent_id = 0");
?>
<ul>
<?php
while($row = $result->fetch(PDO::FETCH_ASSOC)):
?>
<li><?php echo $row['category'] ?></li>
<?php endwhile;?>
</ul>
output;
<ul>
<li>Laptops</li>
<li>Houses</li>
</ul>
but i'm trying to get my Lenovo and HP under Laptop i'd be really happy if you can help me! Thanks.
<?php
include_once("dir/db.php");
$result = $db->query("SELECT * FROM categories WHERE parent_id = 0");
echo "<ul>";
while($row = $result->fetch(PDO::FETCH_ASSOC)):
echo "<li>" . $row['category'] . "</li>";
$sub_result = $db->query("SELECT * FROM categories WHERE parent_id = " . $row['id']);
echo "<ul>";
while($sub_row = $sub_result->fetch(PDO::FETCH_ASSOC)):
echo "<li>" . $sub_row['category'] . "</li>";
endwhile;
echo "</ul>";
endwhile;
echo "</ul>";
?>

mysqli query to fetch row values without loop

I am newbie and need help to resolve my issue.
extract row values without loop.
Table:
----------------
YEAR | SALES
----------------
2011 | 45
2012 | 34
2013 | 23
2014 | 10
2015 | 48
----------------
PHP code:
$sql = "SELECT YEAR FROM MyGuests";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
// output data of each row
while($row = $result->fetch_assoc()) {
echo "YEAR: " . $row["YEAR"]. "<br>";
}
} else {
echo "0 results";
}
looking for solution to output the year value without loop , something similar below
while loop prints all row values , but would like to extract individual year value from query and assign it to a variable
$year1 = $row["YEAR"]
$year2 = $row["YEAR"]
$year3 = $row["YEAR"]
with your current code
$i=1;
while($row = $result->fetch_assoc()) {
${'year'.$i}= $row["YEAR"];
$i++;
//echo "YEAR: " . $row["YEAR"]. "<br>";
}
now you can access $year1; $year2 and so on

Creating a dynamic table with rowspan PHP

How to create a table with data retrieved from MySQL with PHP
-------------------------
| albumID | trackID |
-------------------------
| | 1990 |
- 1 -------------
| | 1991 |
-------------------------
| | 1992 |
- -------------
| 2 | 1993 |
- -------------
| | 1994 |
-------------------------
I can generate a table from the database, but the result will be only like each result in one row
$query = "SELECT albumID, trackID
FROM songs";
$result = mysqli_query($db, $query);
echo "<table>";
echo "<tr>\n";
echo "<th>albumID</th>\n";
echo "<th>trackID</th>\n";
echo "</tr>\n";
while ($data = mysqli_fetch_array($result)) {
echo "<tr>\n";
echo "<td>$data[0]</td>\n";
echo "<td>$data[1]</td>\n";
echo "</tr>\n";
}
echo "</table>\n";
Any help given is really appreciated!
You can do this by using a variable to keep track of the current album and only output the album once as shown below.
$current_album = ''; # initialize tracking var
while ($data = mysqli_fetch_array($result)) {
echo "<tr>\n";
if ($current_album != $data[0]) {
echo "<td>$data[0]</td>\n";
$current_album = $data[0];
} else {
echo "<td> </td>\n"; # insert empty cell
}
echo "<td>$data[1]</td>\n";
echo "</tr>\n";
}
This will have the album ID appearing in the first row for the album. If you want it to be vertically centered you can use rowspan on the td element, but in order to know how many rows each album has you will either need to update your sql query to return that or you can process the results into a multidimensional array and then loop through that to generate the output.
Maybe not the most elegant solution, but should do the trick.
$query = "select albumID as album, group_concat(trackID) as tracks from songs group by albumID";
$result = mysqli_query($db, $query);
echo "<table>";
echo "<tr>\n";
echo "<th>albumID</th>\n";
echo "<th>trackID</th>\n";
echo "</tr>\n";
while ($data = mysqli_fetch_array($result)) {
$tracks = explode(",", $data[1]);
echo "<tr>\n";
echo "<td rowspan=\"".count($tracks)."\">$data[0]</td>\n";
foreach ($tracks as $key => $value) {
echo "<td>$value</td>\n"
}
echo "</tr>\n";
}
echo "</table>\n";
Edit your query to return the numbers of tracks of the album and use that number to create a rowspan only on the first track row. I wrote a little example but I havn't tried if it works.
$query = "SELECT s.albumID, s.trackID,
( SELECT COUNT(*)
FROM songs s2
WHERE s2.albumID = s.albumID )
FROM songs s";
$result = mysqli_query($db, $query);
echo "<table>";
echo "<tr>\n";
echo "<th>albumID</th>\n";
echo "<th>trackID</th>\n";
echo "</tr>\n";
$tmpAlbum = '';
while ($data = mysqli_fetch_array($result)) {
echo "<tr>\n";
echo "<td";
if($data[2] == 1){
echo "<td>$data[0]</td>\n";
}else{
if($data[0] != $tmpAlbum){
echo "<td rowspan=\"".$data[2]."\">$data[0]</td>\n";
}
}
$tmpAlbum = $data[0];
echo "<td>$data[1]</td>\n";
echo "</tr>\n";
}
echo "</table>\n";

Getting a modified preorder tree traversal model (nested set) into a <ul>

I am trying to get my data which is hierarchically set up with a tree traversal model into an < ul> in order to show on my site.
Here is my code:
function getCats($) {
// retrieve all children of $parent
$query = "SELECT max(rght) as max from t_categories";
$row = C_DB::fetchSingleRow($query);
$max = $row["max"];
$result ="<ul>";
$query = "SELECT * from t_categories where lft >=0 and rght <= $max";
if($rs = C_DB::fetchRecordset($query)){
$p_right ="";
$p_left ="";
$p_diff="";
while($row = C_DB::fetchRow($rs)){
$diff = $row["rght"] -$row["lft"];
if($diff == $p_diff){
$result.= "<li>".$row['title']."</li>";
}elseif (($row["rght"] - $row["lft"] > 1) && ($row["rght"] > $p_right)){
$result. "<ul>";
$result.= "<li>".$row['title']."</li>";
}else{
$result.= "<li>".$row['title']."</li>";
}
$p_right = $row["rght"];
$p_left = $row["lft"];
$p_diff = $diff;
}
}
$result.= "</ul>";
return $result;
}
Here is my sample table:
|ID | TITLE | lft| rght |
|1 | Cat 1 | 1 | 16 |
|18 | Cat 2 | 3 | 4 |
|22 | Cat 3 | 5 | 6 |
|28 | Cat 4 | 7 | 8 |
|34 | Cat 5 | 9 | 9 |
|46 | Cat 6 | 11 | 10 |
|47 | Cat 7 | 13 | 12 |
|49 | Cat 8 | 15 | 14 |
Now it outputs something like:
<ul>
<li>Cat 1</li>
<li>Cat 2</li>
<li>Cat 3</li>
<li>Cat 4</li>
<li>Cat 5</li>
<li>Cat 6</li>
<li>Cat 7</li>
<li>Cat 8</li>
</ul>
Can anyone tell me why or how it will output the list in hierarchical a structure?
Related topic
Ok, let's do some bounty hunting ;)
Step 0 - Sanitize example:
As already mentioned, your example data is broken, as it does not define a valid nested set. If you took this data from an app, you should check the insert/delete logic.
So for testing, I used a sanitized version like so:
(MySQL here, as it was the first at hand)
CREATE TABLE t_categories`(
`id` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
`title` VARCHAR(45) NOT NULL,
`lft` INTEGER UNSIGNED NOT NULL,
`rght` INTEGER UNSIGNED NOT NULL,
PRIMARY KEY (`id`)
);
INSERT INTO t_categories (title, lft, rght) VALUES ('Cat 1',1,16);
INSERT INTO t_categories (title, lft, rght) VALUES ('Cat 2',2,3);
INSERT INTO t_categories (title, lft, rght) VALUES ('Cat 3',4,7);
INSERT INTO t_categories (title, lft, rght) VALUES ('Cat 4',5,6);
INSERT INTO t_categories (title, lft, rght) VALUES ('Cat 5',8,13);
INSERT INTO t_categories (title, lft, rght) VALUES ('Cat 6',9,12);
INSERT INTO t_categories (title, lft, rght) VALUES ('Cat 7',10,11);
INSERT INTO t_categories (title, lft, rght) VALUES ('Cat 8',14,15);
Step 1 - Let the database do the ordering
Nested sets where primarily invented as a convenient way of storing trees in databases, as they make it pretty easy to query for subtrees, parent relations and, especially interesting in this case, for order and depth:
SELECT node.title, (COUNT(parent.title) - 1) AS depth
FROM t_categories AS node
CROSS JOIN t_categories AS parent
WHERE node.lft BETWEEN parent.lft AND parent.rght
GROUP BY node.title
ORDER BY node.lft
This will return your set neatly ordered, starting with the root node and continuing to the end in preorder. Most importantly, it will add the depth of each node as a positive integer, indicating how many levels the node is below root (level 0). For the above example data, the result will be:
title, depth
'Cat 1', 0
'Cat 2', 1
'Cat 3', 1
'Cat 4', 2
'Cat 5', 1
'Cat 6', 2
'Cat 7', 3
'Cat 8', 1
In code:
// Grab ordered data
$query = '';
$query .= 'SELECT node.title, (COUNT(parent.title) - 1) AS depth';
$query .= ' FROM t_categories AS node';
$query .= ' CROSS JOIN t_categories AS parent';
$query .= ' WHERE node.lft BETWEEN parent.lft AND parent.rght';
$query .= ' GROUP BY node.title';
$query .= ' ORDER BY node.lft';
$result = mysql_query($query);
// Build array
$tree = array();
while ($row = mysql_fetch_assoc($result)) {
$tree[] = $row;
}
The resulting array will look like this:
Array
(
[0] => Array
(
[title] => Cat 1
[depth] => 0
)
[1] => Array
(
[title] => Cat 2
[depth] => 1
)
...
)
Step 2 - Output as HTML list fragment:
Using while loop:
// bootstrap loop
$result = '';
$currDepth = -1; // -1 to get the outer <ul>
while (!empty($tree)) {
$currNode = array_shift($tree);
// Level down?
if ($currNode['depth'] > $currDepth) {
// Yes, open <ul>
$result .= '<ul>';
}
// Level up?
if ($currNode['depth'] < $currDepth) {
// Yes, close n open <ul>
$result .= str_repeat('</ul>', $currDepth - $currNode['depth']);
}
// Always add node
$result .= '<li>' . $currNode['title'] . '</li>';
// Adjust current depth
$currDepth = $currNode['depth'];
// Are we finished?
if (empty($tree)) {
// Yes, close n open <ul>
$result .= str_repeat('</ul>', $currDepth + 1);
}
}
print $result;
Same logic as recursive function:
function renderTree($tree, $currDepth = -1) {
$currNode = array_shift($tree);
$result = '';
// Going down?
if ($currNode['depth'] > $currDepth) {
// Yes, prepend <ul>
$result .= '<ul>';
}
// Going up?
if ($currNode['depth'] < $currDepth) {
// Yes, close n open <ul>
$result .= str_repeat('</ul>', $currDepth - $currNode['depth']);
}
// Always add the node
$result .= '<li>' . $currNode['title'] . '</li>';
// Anything left?
if (!empty($tree)) {
// Yes, recurse
$result .= renderTree($tree, $currNode['depth']);
}
else {
// No, close remaining <ul>
$result .= str_repeat('</ul>', $currNode['depth'] + 1);
}
return $result;
}
print renderTree($tree);
Both will output the following structure:
<ul>
<li>Cat 1</li>
<li>
<ul>
<li>Cat 2</li>
<li>Cat 3</li>
<li>
<ul>
<li>Cat 4</li>
</ul>
</li>
<li>Cat 5</li>
<li>
<ul>
<li>Cat 6</li>
<li>
<ul>
<li>Cat 7</li>
</ul>
</li>
</ul>
</li>
<li>Cat 8</li>
</ul>
</li>
</ul>
Nitpickers corner: Questioner explicitly asked for <ul>, but ordered unordered lists!? Come on...
;-)
Better Render Tree Function that worked for me (php function to prepare html source for use in jsTree jQuery plugin) instead of the Henrik Opel's one:
function MyRenderTree ( $tree = array(array('name'=>'','depth'=>'')) ){
$current_depth = 0;
$counter = 0;
$result = '<ul>';
foreach($tree as $node){
$node_depth = $node['depth'];
$node_name = $node['name'];
$node_id = $node['category_id'];
if($node_depth == $current_depth){
if($counter > 0) $result .= '</li>';
}
elseif($node_depth > $current_depth){
$result .= '<ul>';
$current_depth = $current_depth + ($node_depth - $current_depth);
}
elseif($node_depth < $current_depth){
$result .= str_repeat('</li></ul>',$current_depth - $node_depth).'</li>';
$current_depth = $current_depth - ($current_depth - $node_depth);
}
$result .= '<li id="c'.$node_id.'"';
$result .= $node_depth < 2 ?' class="open"':'';
$result .= '><ins> </ins>'.$node_name.'';
++$counter;
}
$result .= str_repeat('</li></ul>',$node_depth).'</li>';
$result .= '</ul>';
return $result;}
Result HTML:
<ul>
<li id="c1" class="open"><ins> </ins>ELECTRONICS
<ul>
<li id="c2" class="open"><ins> </ins>TELEVISIONS
<ul>
<li id="c3"><ins> </ins>TUBE</li>
<li id="c4"><ins> </ins>LCD</li>
<li id="c5"><ins> </ins>PLASMA
<ul>
<li id="c14"><ins> </ins>PLASMA1</li>
<li id="c15"><ins> </ins>PLASMA2</li>
</ul>
</li>
</ul>
</li>
<li id="c6" class="open"><ins> </ins>PORTABLE ELECTRONICS
<ul>
<li id="c7"><ins> </ins>MP3 PLAYERS
<ul>
<li id="c8"><ins> </ins>FLASH</li>
</ul>
</li>
<li id="c9"><ins> </ins>CD PLAYERS</li>
<li id="c10"><ins> </ins>2 WAY RADIOS</li>
</ul>
</li>
</ul>
</li>
</ul>
There's a PEAR package for dealing with nested sets: DB_NestedSet.
You might also be interested in the article Managing Hierarchical Data in MySQL.
This should be what you're looking for:
function getCats($left = null, $right = null)
{
$sql = array();
$result = null;
if (isset($left) === true)
{
$sql[] = 'lft >= ' . intval($left);
}
if (isset($right) === true)
{
$sql[] = 'rght <= ' . intval($right);
}
if (empty($sql) === true)
{
$sql[] = 'lft = 1';
}
$sql = 'SELECT * FROM t_categories WHERE ' . implode(' AND ', $sql) . ';';
if ($rs = C_DB::fetchRecordset($sql))
{
// you need to make sure that the query returns
// something to correctly display the ULs
if (empty($rs) === false)
{
$result .= '<ul>' . "\n";
while ($row = C_DB::fetchRow($rs))
{
$result .= '<li>' . $row['title'] . '</li>' . "\n";
$result .= getCats($row['lft'], $row['rght']);
}
$result .= '</ul>' . "\n";
}
}
return $result;
}
To get the HTML for your nested tree you should do:
echo getCats();
Please note that your nested set sample doesn't look right, also you should make sure if I didn't made any mistake invoking your C_DB class, I don't know since I'm not familiarized with it.
Simply loop thru the result will do:
$sql = "SELECT node.name, (COUNT(parent.name) - 1) AS depth
FROM nested_category AS node,
nested_category AS parent
WHERE node.lft BETWEEN parent.lft AND parent.rgt
GROUP BY node.name
ORDER BY node.lft";
$query_result = mysql_query($sql)
$result = "<ul>";
$currDepth = 0;
while($row = mysql_fetch_assoc($query_result))
{
if($row['depth'] > $currDepth)
{
$result .= "<li><ul>"; // open sub tree if level up
}
if($row['depth'] < $currDepth)
{
$result .= str_repeat("</ul></li>", $currDepth - $row['depth']); // close sub tree if level down
}
$result .= "<li>$row['name']</li>"; // Always add node
$currDepth = $row['depth'];
}
$result .= "</ul>";
echo $result;
$linaje='';
$lastnode='';
$sides['izq']=array();
$sides['der']=array();
$print = '<ul>';
foreach ($array as $key1 => $value1){ //Proyectos
if(strpos($info[$key1]['linaje'],'-') !== false)
$compare = strstr($info[$key1]['linaje'],'-',true);
else
$compare = $info[$key1]['linaje'];
if($linaje != ''){
if ($linaje != $compare){
$linaje= $compare;
$sides['izq']=array();
$sides['der']=array();
//for($i=1;$i <= substr_count($lastnode,'`')-substr_count($value1,'`');$i++)
//$print .= '</ul></li>';
}
}
if ($lastnode != '')
for($i=1;$i<= substr_count($lastnode,'`')-substr_count($value1,'`');$i++)
$print .= '</ul></li>';
if (count($sides['der'])>0)
if ($sides['der'][count($sides['der'])-1] > $info[$key1]['der'])
$print .= '<ul>';
$print .= '<li>'.substr($value1,substr_count($value1,'`')).'';
if ($info[$key1]['der'] - $info[$key1]['izq'] == 1)
$print .= '</li>';
if ($key1 == count($info)-1)
for($i=1;$i <= substr_count($lastnode,'`')-1;$i++)
$print .= '</ul></li>';
$sides['der'][] = $info[$key1]['der'];
$sides['izq'][] = $info[$key1]['izq'];
if ($linaje =='')
$linaje = $info[$key1]['linaje'];
$lastnode = $value1;
}
$print .= '</ul>';
echo $print;
the difference in this is that you can render X numbers of trees, this applies to one of my projects. and I use a char as a depth reference when I fetch the rows from the DB
i`m using CROSS JOIN query displaying jsTree jQuery menu; Everything works just great !
The existing table I added a column for the position. However, when I define position and ordered all by position, the corresponding items are not grouped properly. I guess it's a query issue, tried many combinations, but no success.

Nested dropdown

I'm building a form with php/mysql. I've got a table with a list of locations and sublocations. Each sublocation has a parent location. A column "parentid" references another locationid in the same table. I now want to load these values into a dropdown in the following manner:
--Location 1
----Sublocation 1
----Sublocation 2
----Sublocation 3
--Location 2
----Sublocation 4
----Sublocation 5
etc. etc.
Did anyone get an elegant solution for doing this?
NOTE: This is only psuedo-code.. I didn't try running it, though you should be able to adjust the concepts to what you need.
$parentsql = "SELECT parentid, parentname FROM table";
$result = mysql_query($parentsql);
print "<select>";
while($row = mysql_fetch_assoc($result)){
$childsql = "SELECT childID, childName from table where parentid=".$row["parentID"];
$result2 = mysql_query($childsql);
print "<optgroup label=\".$row["parentname"]."\">";
while($row2 = mysql_fetch_assoc($result)){
print "<option value=\"".$row["childID"]."\">".$row["childName"]."</option>\n";
}
print "</optgroup>";
}
print "</select>";
With BaileyP's valid criticism in mind, here's how to do it WITHOUT the overhead of calling multiple queries in every loop:
$sql = "SELECT childId, childName, parentId, parentName FROM child LEFT JOIN parent ON child.parentId = parent.parentId ORDER BY parentID, childName";
$result = mysql_query($sql);
$currentParent = "";
print "<select>";
while($row = mysql_fetch_assoc($result)){
if($currentParent != $row["parentID"]){
if($currentParent != ""){
print "</optgroup>";
}
print "<optgroup label=\".$row["parentName"]."\">";
$currentParent = $row["parentName"];
}
print "<option value=\"".$row["childID"]."\">".$row["childName"]."</option>\n";
}
print "</optgroup>"
print "</select>";
Are you looking for something like the OPTGROUP tag?
optgroup is definitely the way to go. It's actually what it's for,
For example usage, view source of http://www.grandhall.eu/tips/submit/ - the selector under "Grandhall Grill Used".
You can use and space/dash indentation in the actual HTML. You'll need a recusrive loop to build it though. Something like:
<?php
$data = array(
'Location 1' => array(
'Sublocation1',
'Sublocation2',
'Sublocation3' => array(
'SubSublocation1',
),
'Location2'
);
$output = '<select name="location">' . PHP_EOL;
function build_items($input, $output)
{
if(is_array($input))
{
$output .= '<optgroup>' . $key . '</optgroup>' . PHP_EOL;
foreach($input as $key => $value)
{
$output = build_items($value, $output);
}
}
else
{
$output .= '<option>' . $value . '</option>' . PHP_EOL;
}
return $output;
}
$output = build_items($data, $output);
$output .= '</select>' . PHP_EOL;
?>
Or something similar ;)
Ideally, you'd select all this data in the proper order right out of the database, then just loop over that for output. Here's my take on what you're asking for
<?php
/*
Assuming data that looks like this
locations
+----+-----------+-------+
| id | parent_id | descr |
+----+-----------+-------+
| 1 | null | Foo |
| 2 | null | Bar |
| 3 | 1 | Doe |
| 4 | 2 | Rae |
| 5 | 1 | Mi |
| 6 | 2 | Fa |
+----+-----------+-------+
*/
$result = mysql_query( "SELECT id, parent_id, descr FROM locations order by coalesce(id, parent_id), descr" );
echo "<select>";
while ( $row = mysql_fetch_object( $result ) )
{
$optionName = htmlspecialchars( ( is_null( $row->parent_id ) ) ? "--{$row->descr}" : "----{$row->desc}r", ENT_COMPAT, 'UTF-8' );
echo "<option value=\"{$row->id}\">$optionName</option>";
}
echo "</select>";
If you don't like the use of the coalesce() function, you can add a "display_order" column to this table that you can manually set, and then use for the ORDER BY.

Categories