mar2195
asked on
PHP - Create UL Nested Lists From Flatfile
(Before anyone asks... I cannot use a MySQL database for this project.)
Using PHP, I need to create nested UL's from a flatfile database. The issue that I'm having is that I don't want duplicate items displayed. I could explain further, but if you'll take a look at the code below, you'll see the data and the goal. Thanks.
FLATFILE DATA:
section|category|service
Section One|Category One|
Section One|Category Two|SC1
Section One|Category Two|SC2
Section One|Category Two|SC3
Section One|Category Two|SC4
Section One|Category Three|
Section Two|Category Four|SC5
Section Two|Category Four|SC6
Section Three|Category Five|SC7
HTML GOAL OUTPUT:
Using PHP, I need to create nested UL's from a flatfile database. The issue that I'm having is that I don't want duplicate items displayed. I could explain further, but if you'll take a look at the code below, you'll see the data and the goal. Thanks.
FLATFILE DATA:
section|category|service
Section One|Category One|
Section One|Category Two|SC1
Section One|Category Two|SC2
Section One|Category Two|SC3
Section One|Category Two|SC4
Section One|Category Three|
Section Two|Category Four|SC5
Section Two|Category Four|SC6
Section Three|Category Five|SC7
HTML GOAL OUTPUT:
<ul class="section">
<li>Section One
<ul class="category">
<li>Category One</li>
<!-- no service -->
</ul> <!-- /category -->
<ul class="category">
<li>Category Two</li>
<ul class="service">
<li>SC1</li>
<li>SC2</li>
<li>SC3</li>
<li>SC4</li>
</ul> <!-- /service -->
</li>
</ul> <!-- /category -->
<ul class="category">
<li>Category Three</li>
<!-- no service -->
</ul> <!-- /category -->
</li>
</ul> <!-- /section -->
<ul class="section">
<li>Section Two
<ul class="category">
<li>Category Four</li>
<ul class="service">
<li>SC5</li>
<li>SC6</li>
</ul> <!-- /service -->
</li>
</ul> <!-- /category -->
</li>
</ul> <!-- /section -->
<ul class="section">
<li>Section Three
<ul class="category">
<li>Category Five</li>
<ul class="service">
<li>SC7</li>
</ul> <!-- /service -->
</li>
</ul> <!-- /category -->
</li>
</ul> <!-- /section -->
What is the issue? Have you tried to write any of the PHP code yet? If so, please show us your start, thanks. ~Ray
Look at fgetcsv to read the lines into an array.
Then use a standard catchup processing algorithm to run through the array
i.e. maintain a category and section variable set to the current section and category.
For each item in the array check to see if the section matches and category matches - if they do then you are in a service output loop - loop until category and or section changes.
At this point close any open <ul>'s and update the section and category vars.
There are a number of ways to do this - but as Ray says show us how far you have got.
Then use a standard catchup processing algorithm to run through the array
i.e. maintain a category and section variable set to the current section and category.
For each item in the array check to see if the section matches and category matches - if they do then you are in a service output loop - loop until category and or section changes.
At this point close any open <ul>'s and update the section and category vars.
There are a number of ways to do this - but as Ray says show us how far you have got.
ASKER
My 1st attempt... thinking that I need to first check if the "section" exists, then assign the current "section" to a "section_last" to compare the next "section" with the current "section" value ... and if not, print the "section" ... and then onto the category. I didn't code the "service" value section because I wasn't haven't any success with the section & category values. It seems that I'm having an issue with either the 'logic' behind this or maybe there's a method for comparing the past value in the loop with the next value that PHP offers that I'm missing.
<?php
$section = '';
$category = '';
$service = '';
$section_last = '';
$category_last = '';
$service_last = '';
$x = 0;
$file = fopen("categories_data.txt", "r");
if (!$file) { echo 'ERROR: Unable to open file: <strong>'.$file.'</strong>'; }
fgets($file); // IGNORE FIRST LINE IN FLATFILE - column names
while (!feof($file) ) {
$lines = fgets($file);
$ele = explode('|', $lines);
$section = $ele[0];
$category = $ele[1];
$service = $ele[2];
$service = str_replace(array("\n", "\r", "\r\n", "\n\r"), '',$service);
if(strlen($section)>0) {
if(!($section == $section_last)) {
echo '
<ul>
<li>'.$section;
$section_last = $section;
$x++;
}
}
echo '
<ul><li>'.$category.' > '.$service.'</li></ul>
';
if($x) {
if($section != $section_last) {
echo '
</li>
</ul>
';
}
}
} // end $data_file WHILE
fclose($file);
?>
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
@julianH ... YES YES YES!!! As I thought, this was much more involved than I anticipated. My logic was way too simple - thinking: Just check the previous section/category/service against the new data in the loop. So I never would've nailed this.
I can tell you that I searched high and low on the web for even an explanation/tutorial about this situation. Flatfile help on the web is minimal vs other database coding. I also GREATLY appreciate your explanations along with the code. When I have a project such as this, I want to learn something rather than just COPYING/PASTING the code.
There are very specific issues using a flatfile as opposed to other database methods. Other methods allow for nearly direct access to data - and for data comparisons. "Holding" data for comparison seems a little more involved using a flatfile.
Thanks again.
I can tell you that I searched high and low on the web for even an explanation/tutorial about this situation. Flatfile help on the web is minimal vs other database coding. I also GREATLY appreciate your explanations along with the code. When I have a project such as this, I want to learn something rather than just COPYING/PASTING the code.
There are very specific issues using a flatfile as opposed to other database methods. Other methods allow for nearly direct access to data - and for data comparisons. "Holding" data for comparison seems a little more involved using a flatfile.
Thanks again.
ASKER
AWESOME!! I hope this question / solution makes it into the web's searches. It's sorely needed!
You are most welcome - and thanks for the points.
ASKER
@julianH ...
One additional question...
If I want to edit/add things within the loop, where would I enter this info?
I've made a few attempts, but I can't seem to get "into" the loop correctly.
Meaning... if I want to add an incrementing $i for an ID number per category, where would that get added? I can't figure out where to put the $i and the $i++ ?? Thanks.
One additional question...
If I want to edit/add things within the loop, where would I enter this info?
I've made a few attempts, but I can't seem to get "into" the loop correctly.
Meaning... if I want to add an incrementing $i for an ID number per category, where would that get added? I can't figure out where to put the $i and the $i++ ?? Thanks.
I would do it with a static variable in the dump_services function like so
function dump_services(& $lines, $category)
{
// Make the variable static so each time
// we come back to this function the old value is remembered
static $categoryid = 1;
// Add the ID and increment in the same operation
echo TAB2 . '<ul class="category" id="' . sprintf("category%03d", $categoryid++) .'">' . PHP_EOL;
echo TAB . TAB2 . '<li>' . $category . PHP_EOL;
...
ASKER
Thanks. Since I needed the increment number throughout the loop for my jQuery code, I removed the category%03d and put the NUM var as needed in the loop and then put the ++ at the end of the function. Works fine. Thanks again.
ASKER
I noticed that I cannot access the $section variable/value from the dump_categories function in the dump_services. Is there a way to make this variable global?
You might want to post a new question about that. You can make variables global with the PHP global keyword. Whether it is a good or bad idea to make variables global is an entirely different line of reasoning, and most professional programmers would stay away from global variables.
ASKER
@Ray_Paseur ... I may have used the word global incorrectly. I simply meant that I wanted the $section var value in the dump_categories function to be accessible within the dump_services function. Thanks.
Then you will still have to use the global keyword
Any variables declared outside the function are accessible only if declared global inside the function
function dump_categories( ... )
{
global $section;
}
A way around this is as follows
function get_next_section()
{
static $section = 0;
return $section++;
}
Then you can get the next value of $section anywhere in the application
$next = get_next_section();
Any variables declared outside the function are accessible only if declared global inside the function
function dump_categories( ... )
{
global $section;
}
A way around this is as follows
function get_next_section()
{
static $section = 0;
return $section++;
}
Then you can get the next value of $section anywhere in the application
$next = get_next_section();
ASKER
Ah! Yep. That's what I was missing. How do I get the NEXT. Got it. Thanks,