Link to home
Start Free TrialLog in
Avatar of mar2195
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:
<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 -->

Open in new window

Avatar of Ray Paseur
Ray Paseur
Flag of United States of America image

What is the issue?  Have you tried to write any of the PHP code yet?  If so, please show us your start, thanks. ~Ray
Avatar of Julian Hansen
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.
Avatar of mar2195
mar2195

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);
?>

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of Julian Hansen
Julian Hansen
Flag of South Africa image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of mar2195

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.
Avatar of mar2195

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.
Avatar of mar2195

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.
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;
...

Open in new window

Avatar of mar2195

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.
Avatar of mar2195

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.
Avatar of mar2195

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();
Avatar of mar2195

ASKER

Ah!  Yep.  That's what I was missing.  How do I get the NEXT.  Got it.  Thanks,