I have been developing a small site and i have done mostly everything reading through forums, but i can't seem to find a solution for the problem i have,
Trying to create a dynamic menu system using the following structure below from a pre-existing database i have been working from.

Ultimately i want a drop down menu system but i want it to be created automatically through loop statements?

CATEGORY_ID NAME
1 Cameras
2 Cameras>Camera Heads
3 Cameras>Camera Heads>SD
4 Cameras>Camera Heads>HD
5 Cameras>Camcorders
6 Cameras>Camcorders>SD
7 Cameras>Camcorders>HD
8 Camera Accessories
9 Camera Accessories>Matte Boxes
13 Lenses
14 Lenses>Broadcast
15 Lenses>Broadcast>SD
16 Lenses>Broadcast>HD
17 Lenses>Professional
18 Lenses>Professional>Specialist
19 Lenses>Adaptors
20 Lenses>Converters
21 Lenses>Controls
22 Lenses>Follow Focus
etc..

This is the code i have been using, been trying for a few days to get it to work:

function gen($id)
{
if(isset($id))
{
print_r($id);

}else{
continue;
}


}

function rentalmenu_Generator()
{
include('oracleonnect.php');

$query = oci_parse($conn,"SELECT HIRE_CATEGORY.* FROM  WEBEQUIPMENT.HIRE_CATEGORY ORDER BY NAME");
ociexecute($query);
echo "<div id='container'>";
echo "<div id='content'>";
echo "<div class='menu-nav'>";
$call = array();
$i = 0;
while ($row = oci_fetch_array($query, OCI_BOTH))
{

$catid =  $row['CATEGORY_ID'];
$menuname = $row['NAME'];

$strip = explode(">", $menuname);
//$toplevel = $name;
//if (strpos($menuname,">")===false)
//{
//$toplevel = $menuname;
//}else{
//$submenu = explode(">", $menuname);
//}
//echo $toplevel;
//echo "<br />";

$test = count($strip, COUNT_RECURSIVE);
//$max = max($strip);
//echo $max;

if ($test == 1)
{
$toplevel = $strip[0];
echo "<ul><li class='start'><a href='".$_SERVER['PHP_SELF']."?cat=".$catid."'>".$toplevel."</a></li></ul>";
$parents[] = $toplevel;

}else{

$toplevel2 = $strip[1];
echo "<li class='sub'><a href='".$_SERVER['PHP_SELF']."?cat=".$catid."'>".$toplevel2."</a>";
$submenu1[] = $toplevel2;
$call[$toplevel]  = $toplevel2;
if (isset($strip[2]))
{

$toplevel1 = $strip[2];
echo "--><a href='".$_SERVER['PHP_SELF']."?cat=".$catid."'>".$toplevel1."</a></li>";
$submenu2[] = $toplevel1 ;
$call[$toplevel] = $toplevel1;
}else{
echo "</li>";
}
gen($call);
}


$i++;			
//echo $i;


}
//print_r($call);




$num_rows = oci_num_rows($query);
$maxrecords = $num_rows;
$countparents = count($parents);



echo "<br />";echo "<br />";echo "<br />";echo "<br />";
$t = 0;

while($countparents < $maxrecords )

{
if(isset($parents[$t]))
{
echo $parents[$t];
$sub = 0;
if(isset($submenu1[$sub]))
{
while($submenu1[$sub])
{
echo "<br />";
echo "-->".$submenu1[$sub];

$sub++;
continue 1;
}
}
echo "<br />";

}else{
break;
}
$t++;
$countparents++;
}

//print_r($parents);
//print_r($submenu1);


echo "<br />";
echo "</div>";
echo "</div>";
echo "</div>";
ocifreestatement($query);
oci_close($conn);

}

The Outout i am trying to achieve:

<ul>
<li class="parent">Cameras</li>
<ul>
<li class="child">Camera Heads</li>
			<ul>
                <li class="subchild">SD</li>
                <li>HD</li>
            </ul>
<li class="child">Camcorders</li>
		<ul>
			<li class="subchild">SD</li>
			<li class="subchild">HD</li>
		</ul>
</ul>
etc....
</ul>

Hopefully this will make sense to someone? 🙂

    it looks to me as if you are going about it the wrong way

    hard to tell without seeing your data..
    but I think you must be storing a complete entry as "Cameras>Camera Heads>HD"
    is that correct?

    if so you need to check out "recursive trees"
    basically you should store each item separately
    eg:
    Cameras
    Camera Heads
    HD
    and lets say each one has an id (I am using random numbers as that it how it will end up)..so:
    id : name
    2: Cameras
    7: Camera Heads
    99: HD

    and then each one also has the parent id, so :
    id : name : parent_id
    2 : Cameras : 0
    7 : Camera Heads : 2
    99 : HD : 7

    then you use that structure to place everything
    so I guess this means starting again

      the structure in the database i cannot change.

      I was thinking that if i can sort it all with 'NAME' then i can create a loop to search through the results so when it returns one item I know that it is a parent ID and because i have sorted it by 'NAME' every time it hits a one item in the row it will start the parent ID again. But i am not sure how to do that... Is it possible to use a While loop and put another While loop inside to step through the Rows in a table?

      Anyway that is my logic, i have seen a few design in this way, but never been able to work out the logic to make it dynamic.

      Anybody has any ideas? i have been on this problem for about 2 days and i am going round in circles.

        ah.. sorry, easy to miss key phrase "existing data"

        well I'd be inclined to get it into arrays and do the sorting with php
        that may be because I know my round a few of the array routines
        - I mean you're going to have resort it as order by name is not going to be exactly as you want to display it, I think

        I have done very much the same thing but with normalised data, and even that I use arrays to get the tree structure to end up with a dropdown nav with flyouts

          I was afraid of that, because i might as well just design the menu in html no point in trying to automate it, because everytime a new menu item is added i will still have to put it together manually, i was looking for a solution where the menu can build itself from the contents in that table.

          I'm looking into recursive arrays but i don't fully understand them which is why i had joined a forum to get some more expert advice.

          I know its been done on other websites, but i don't have access to the source.

          It's ashame because it is the last piece of the site which i want to automate.

            you should be able to automate it !

            you just need to explode the long name recursively so you rebuild the structure as if each item had a parent - in other words pretty much as you are doing

            but without going through your code step by step it's hard to know where its wrong

            what problem are you getting?

            there's two things to do:
            a: get the output in the order you want (as if they are a plain list of pages)
            b: put it in the correct '<ul><li>' structure
            I found part b the trickiest bit !

              Well what i have done is:

              $strip = explode(">", $menuname); obviously with this i have separated everything with ">"

              the next part:

              $test = count($strip, COUNT_RECURSIVE);

              I wanted to count how many words after the split remain.

              Then:
              If the row has one word do the following: This bit works fine;
              if ($test == 1)
              {
              $toplevel = $strip[0];
              echo "<ul><li class='start'><a href='".$_SERVER['PHP_SELF']."?cat=".$catid."'>".$toplevel."</a></li></ul>";
              $parents[] .= $toplevel;<---- this is to check that it has collected all the parents IDs
              }else{

              Now the next bit is tricky im not sure how to approach but i was hoping to maybe use a loop to check the next row to place everything under that current parent id, does it make sense?

              I have confused myself many times with the logic, keep forgetting the while loop checks one row at a time, and that is the issue i have, because to place ul's and li's is difficult without being able to close them properly

                ok - yes I've been there.. makes complete sense
                and I agree the logic for closing the <ul> the right number of times is a major pain

                (I found it easier to work with everything in a php array - I know you can treat a db and an array in much the same way but array code is less typing)

                as it goes through it needs to know the level the previous item was and the level the next item is

                if level is "less" then close the '</ul>' by the number of times it is "less than"
                if level is greater, open a <ul> (as you know it will never open two uls in one go)

                I did end up debugging with large doses of print_r !

                  yep i have been using print_r alot to show me what the code was doing very useful i have found,,, been scouring through php manual to find any functions which could help, i'm pretty sure there is something i am missing out or don't understand.

                  im really stuck i feel don't have the experience yet to do something like this.

                  I was considering using a class to solve this solution but that requires more expertise than i have.

                  Do you have anymore ideas or the logic/structure i should use to put this together? I don't need the solution just how i should be thinking about doing this..

                    I forgot its not just a plain deal with closing uls - 'li' tags are bound up in it -
                    I mean they don't just wrap every entry

                    I've looked at my mess of code and cant see any key part
                    this may be of help

                     if($rootlevel<$prevlevel){
                     	 $ulshift=$prevlevel-$rootlevel;
                    
                    	for($u=0;$u<$ulshift;$u++){
                     	echo "</li>\n"; 
                     	echo "\t</ul>\n\n";
                      	}
                     }
                    
                    	if($rootlevel>$prevlevel) {
                    		echo "\n\n\t<ul style=' width: 160px;'>\n"; 
                    		} else { 
                    		echo "</li>\n"; 
                    		}

                    and I had to add a very end part to clean up

                    if($prevlevel>=1 ){
                     	$ulshift=$prevlevel-1;
                     	for($u=0;$u<=$ulshift;$u++){
                    	echo "\n</li>"; 
                    	 echo "\n</ul>";
                    	 }
                    	 }

                      but with what i have written so far should be ok right?

                      because im not sure that after the 'else' that i have it correct because the second word after the '>' is also repeated when there is a third word in that row and so on. so I either put a limit on how many words there should be which will be a bit of bummer or put a loop in to count the words again and duplicate the code.

                      I have attached a jpg so you can see what i am getting,

                      I will definately explore the UL li statements aswell to see what i can conjure up..

                        I think its down to you now - try and come up with as general a solution as you can and then bodge in the additional items you need for the third levels

                        i.e. make it work showing the single phrase (it is a phrase your dealing with, not a word e.g. "field prodcution")

                        you're not getting confused over your "counts" are you??

                        string='abc>xx and more ex>fff';
                        explode string on '>' ... then count will give you 3
                        and ournewarray[1] will be 'xx and more ex'

                        sorry if you know that but need to make sure

                        a bit of str_replace might get you out of a hole as a quick hack if it's extra words you want to remove

                          oh yeah str_replace might help,

                          well with the count after the first else in my code there is this:
                          Because if the count is only '1' then the next statement is true so there is more than one..

                          $toplevel2 = $strip[1];
                          echo "<li class='sub'><a href='".$_SERVER['PHP_SELF']."?cat=".$catid."'>".$toplevel2."</a>";
                          $submenu1[] = $toplevel2;
                          $call[$toplevel] = $toplevel2;
                          if (isset($strip[2])) <--- and then again here, if there is a third word after '>'
                          {

                          $toplevel1 = $strip[2];
                          echo "--><a href='".$_SERVER['PHP_SELF']."?cat=".$catid."'>".$toplevel1."</a></li>";
                          $submenu2[] = $toplevel1 ;
                          $call[$toplevel] = $toplevel1;
                          }else{
                          echo "</li>";
                          }

                          But if you remember i exploded everything with '>' everything is counted as 1 afer each '>'

                          I have attached a picture to show what i am trying to achieve a picture can explain this better than writing long pieces of explanation hehe.

                          thanks for your help... definately cleared a few things up for me.

                          but if there is a completely different way of writing this then i dont mind doing that, just want a good solution.

                            it does look close to how my code ended up
                            I guess you need to see how it works out and where it is going wrong

                            the display css is another matter!

                              I have a drop down script ready to go, just need the formatting of the menus to be correct for it to work properly... So i guess i need to figure out how to manipulate the UL and the LI when it loops through...

                                Write a Reply...