tags:

views:

1343

answers:

3

Hi,

I have three tables in a MySQL database.

  1. collection
  2. category
  3. subcategory

I use the following function to retrieve data from these tables to display as a tree:

function create_menu($params)
    {
     //retrieve menu items 
     //get collection 
     $collection = get('xxcollection') ;

     foreach($collection as $c) 
     {
      echo '<div class="parent" style="direction:rtl">';
        echo  '<img src="../images/dtree/minus.gif" align="absmiddle" class="parent_item" id="minus" />
        <img src="../images/dtree/base.gif" align="absmiddle" id="base">
        '.$c['xcollectionname'] ;  
     //get categories 
      $cat = get_where('xxcategory' , array('xcollectionid'=>$c['xcollectionid'])) ; 


      foreach($cat as $item)
      {
       echo '<div class="node" >';
        echo  '<img src="../images/dtree/plus.gif" align="absmiddle" class="node_item" id="plus" />
        <img src="../images/dtree/folder.gif" align="absmiddle" id="folder">
        '.$item['xcatname'] ; 
         $subcat = get_where('xxsubcategory' , array('xcatid'=>$item['xcatid'])) ;

         foreach($subcat as $val)
         { 
          echo  '<div class="sub_node" style="display:none">' ; 
           echo  '<img src="../images/dtree/join.gif" align="absmiddle" style="padding-left:2px;" />
           <a id="'.$val['xsubcatid'].'" href="javascript:void(0)" onclick="getProduct(this , event)" class="sub_node_links"  >
           '.$val['xsubcatname'].'</a>'; 

          echo '</div>';
         }
       echo '</div>';
      } 
      echo '</div>';
     }

    }
  1. How can I determine the first and last iteration in the foreach loop?
  2. Is it the correct way to retrieve data to be displayed as a tree?
  3. I know it's not standard to use <div> tag to display a tree-like menu. I prefer to use nested <ul>s. However, I always have problems with <ul> in IE. I hope to get some advices or resources on how to use <ul> tags which work in different web browsers.
+9  A: 
  1. You could use a counter:

    $i = 0;
    $len = count($array);
    foreach ($array as $item) {
        if ($i == 0) {
            // first
        } else if ($i == $len - 1) {
            // last
        }
        // …
        $i++;
    }
    
  2. Your method requires a database query for every single collection, category and subcategory. So if you have 10 collections, 100 categories and 1000 subcategories, you will have at least 1110 database queries.

    You should try to do it with just one query (see table joins) or at least one query per table.

  3. A proper used list is always better than a div soup. So try to use ul and li.

Gumbo
+3  A: 

You could remove the first and last elements off the array and process them separately.
Like this:

<?php
$array = something();
$first = array_shift($array);
$last = array_pop($array);

// do something with $first
foreach ($array as $item) {
 // do something with $item
}
// do something with $last
?>

Removing all the formatting to CSS instead of inline tags would improve your code and speed up load time.

You could also avoid mixing HTML with php logic whenever possible.
Your page could be made a lot more readable and maintainable by separating things like this:

<?php
function create_menu($params) {
  //retirive menu items 
  //get collection 
  $collection = get('xxcollection') ;
  foreach($collection as $c) show_collection($c);
}

function show_subcat($val) {
  ?>
    <div class="sub_node" style="display:none">
      <img src="../images/dtree/join.gif" align="absmiddle" style="padding-left:2px;" />
      <a id="'.$val['xsubcatid'].'" href="javascript:void(0)" onclick="getProduct(this , event)" class="sub_node_links"  >
        <?php echo $val['xsubcatname']; ?>
      </a>
    </div>
  <?php
}

function show_cat($item) {
  ?>
    <div class="node" >
      <img src="../images/dtree/plus.gif" align="absmiddle" class="node_item" id="plus" />
      <img src="../images/dtree/folder.gif" align="absmiddle" id="folder">
      <?php echo $item['xcatname']; ?>
      <?php 
        $subcat = get_where('xxsubcategory' , array('xcatid'=>$item['xcatid'])) ;
        foreach($subcat as $val) show_subcat($val);
      ?>
    </div>
  <?php
}

function show_collection($c) {
  ?>
    <div class="parent" style="direction:rtl">
      <img src="../images/dtree/minus.gif" align="absmiddle" class="parent_item" id="minus" />
      <img src="../images/dtree/base.gif" align="absmiddle" id="base">
      <?php echo $c['xcollectionname']; ?>
      <?php
        //get categories 
        $cat = get_where('xxcategory' , array('xcollectionid'=>$c['xcollectionid']));
        foreach($cat as $item) show_cat($item);
      ?>
    </div>
  <?php
}
?>
Carlos Lima
A: 

1: Why not use a simple for statement? Assuming you're using a real array and not an Iterator you could easily check whether the counter variable is 0 or one less than the whole number of elements. In my opinion this is the most clean and understandable solution...

$array = array( ... );

$count = count( $array );

for ( $i = 0; $i < $count; $i++ )
{

    $current = $array[ $i ];

    if ( $i == 0 )
    {

        // process first element

    }

    if ( $i == $count - 1 )
    {

        // process last element

    }

}

2: You should consider using Nested Sets to store your tree structure. Additionally you can improve the whole thing by using recursive functions.

okoman