views:

16

answers:

1

I've made some search on the forum without any good answers for my problem. If I missed something, feel free to link me to the question!

What I need to do is simple: a function that returns an array of the full tree of my categories and items. I only have 1 depth (item and a cat_id), so no recursion involved (though if you have a recursive solution, I would gladly accept it).

Right now, I've done this, but it's pretty bad, since I do multiple queries...

function build_tree()
{
    global $wpdb;

    $cats = $wpdb->get_results("SELECT * FROM wp_catering_cats");


    foreach($cats as &$cat)
    {
      $id = $cat->id;

      $cat->items = $wpdb->get_results("SELECT * FROM wp_catering_items WHERE cat_id = $id");
    }

    return $cats;
}

My tables are really simple:

wp_catering_items

id, cat_id, name, price

wp_catering_cats

id, name

Here is an exemple the results array I want:

    Array
    (
        [0] => array
            (
                [id] => 1
                [name] => Cat #1
                [items] => Array
                    (
                        [0] => array
                            (
                                [id] => 1
                                [cat_id] => 1
                                [name] => Item #1
                                [price] => 5
                            ),
                        ...

                    )

            ),
           ...
   );

If something is not clear, feel free to comment!

Thanks!

EDIT

I've made some modifications using the code bellow, but I' pretty sure there's a neater way to do this. Having to order one DESC and one ASC just doesn't sounds right..

function build_tree()
{
    global $wpdb;

    $cats = $wpdb->get_results("SELECT * FROM wp_catering_cats ORDER BY id DESC");
    $items = $wpdb->get_results("SELECT * FROM wp_catering_items ORDER BY cat_id ASC");

    $item = array_pop($items);

    foreach($cats as &$cat)
    {   
        while($item->cat_id == $cat->id)
        {
            $cat->items[] = $item;
            $item = array_pop($items);
        }
    }

    print_r($cats);
}
+2  A: 

If you are just trying to optimize, then do the simple thing, instead of only grabbing the items for the specific cat you are on, grab all the items at once, and order them by catID. Then loop through your cats, and pop items off your item results until you hit the next cat.

function build_tree()
{
    global $wpdb;

    $cats = $wpdb->get_results("SELECT * FROM wp_catering_cats order by cat_id asc");
    $items = $wpdb->get_results("SELECT * FROM wp_catering_items ORDER BY cat_id asc");

    foreach($cats as &$cat)
    {
      $id = $cat->id;
      $item = array_pop($items)
      while($item['cat_id'] == $id)
      {
        $cats->item[] = $item;
        $item = array_pop($items)
      }
      #do a little bookkeeping so you next cat gets its first item, and zero item cats get skipped.

    }
}

Update: Thanks for the comment.. Forgot to add the pop in the while loop!

Second update: use array_shift instead of array_pop if you don't want reverse ordering to be a problem...

Zak
It should be faster to run queries without ORDER BY and create array $catsById [$catId] = $cat; to make it easy to access category by id.
Naktibalda
You only pop the item once per iteration? Because it looks like this will cause an infinite loop.
all-R
Look at the EDIT in my post, You have to first pop outside the foreach otherwise you will pop off the first item of your new cats (the one that broke in the while loop). Also, since the foreach starts from the beginning, you need to order the categories DESC... There must be a neater way to do this :o But for sure, this solution is still better than the first I had...
all-R