1

I'm trying to implement a category system on my website. The problem is that a category can have child. So far, my table category looks like that :

id, name, parent_id

So far, I made a loop, but it only works for 2 levels. Here is my code :

for($i=0;$i<count($data);$i++){
    $tree[$data[$i]->name] = array();
    for($j=0;$j<count($data);$j++){
        if($data[$j]->parent_id == $data[$i]->id){
            $tree[$data[$i]->name][] = $data[$j]->name;
        }
    }
}

It return me an array as it :

Array
(
    [0] => Array
        (
            [1] => Cat1
            [children] => Array
                (
                    [12] => sub cat 1
                    [13] => sub cat 2
                    [14] => sub cat 3
                )

        )

    [1] => Array
        (
            [2] => Cat2
        )

    [2] => Array
        (
            [3] => Cat3
        )
)

How can I make it efficient and recursive to have something more like :

Array
(
    [0] => Array
        (
            [1] => Cat1
            [children] => Array
                (
                    [12] => sub cat 1
                    [13] => sub cat 2
                    [14] => sub cat 3
                        [children] => Array
                            (
                                [1] => sub sub cat 1
                            )
                )

        )

    [1] => Array
        (
            [2] => Cat2
        )

    [2] => Array
        (
            [3] => Cat3
        )
)

Thanks for your help

EDIT

I'm working on Zend, and it return me the data as it :

Zend_Db_Table_Rowset Object
(
    [_data:protected] => Array
        (
            [0] => Array
                (
                    [id] => 1
                    [name] => Cinema
                    [type] => category
                    [slug] => cinema
                    [parent_id] => -1
                )

            [1] => Array
                (
                    [id] => 2
                    [name] => Horror
                    [type] => category
                    [slug] => horror
                    [parent_id] => 1
               )
lkartono
  • 2,323
  • 4
  • 29
  • 47

3 Answers3

2

If you want to apply this type of structure best to use child in other table with parent id as a foreign key. so with that u can have recursive category posting. so the table structure will be like this

ch_id, parent_id, child
Shwet
  • 1,848
  • 1
  • 24
  • 35
  • Hi, yes I know, but unfortunately, I don't have the choice, I have to use it the way it is now – lkartono Apr 04 '13 at 09:04
  • up to which level u want nested category??????if u have 2-3 layer than your code is perfact with one more for loop... – Shwet Apr 04 '13 at 09:06
  • There's no limit of nested level. Should I just use 2 tables in that case? – lkartono Apr 04 '13 at 09:31
  • than it will be better to use two tables...so that query will be shared on both tables and will make some happiness for u – Shwet Apr 04 '13 at 11:07
0

You should check out Nested Sets, a methodology to store and retrieve date trees in/out of relational databases (what in fact your categories are). For this, you have to adapt your database scheme a little bit (as described in the link or in the several tutorials about nested sets). For PHP, there are several libraries providing Nested Set capabilities, for instance this list.

Community
  • 1
  • 1
strauberry
  • 4,189
  • 5
  • 34
  • 50
0

This should help you out. It Iterates over every member of the array and checks it's position in the tree structure per level and dependency.

function get_children($data, $parent_id = false) {
  $result = array();
  foreach ($data as $i => $content) {
    if ($parent_id != false && $content['id'] != $parent_id)  # other levels
      continue;
    if ($parent_id === false && !empty($content['parent_id'])) # top level
      continue;

    $leaf = array(
      'id' => $content['id'],
      'parent_id' => $content['parent_id'],
      'name' => $conten['name']
    );
    $leaf['children'] = get_children($data, $leaf['id']);
    $result[$leaf['id']] = $leaf;
  }
  return $result;
}

$result =  get_children($data);
print_r($result);

Edit: bug fixes

scones
  • 3,317
  • 23
  • 34
  • Hi, thanks but still not working but I'm closer to solve it now. Actually this line `if ($content['id'] == $data['parent_id']) {` can't work since $data is an array of all categories so I can't access by $data['parent_id'] directly – lkartono Apr 04 '13 at 09:22
  • @user1965817 ah, you're right, wait i fix that. will be a tad bit slower though – scones Apr 04 '13 at 09:24
  • Hmm, yeah you were right, it's too slow. I've got `Fatal error: Allowed memory size`, so I may go for 2 tables in that case, will be maybe much more simple. Thought? – lkartono Apr 04 '13 at 09:30
  • @user1965817 allowed memory size should not kick in. at least not if you just have a few thousand categories. This just means, that one of the break conditions is not working. Is you data cyclical? – scones Apr 04 '13 at 09:41