0
votes

I am trying to make a category tree which accepts n count of sub-categories for each category. I got some code from the net and modified it for my CI but I cannot get the exact result that I want.

I have very simple DB:

id, parent_id, title

If parent_id = 0 then it's main category, if not then it's sub-category of the saved one.

This is the method I have

public function all_categories($parent_id = 0, $categoriesArray = '', $i = 0) {
        if(!is_array($categoriesArray))
            $categoriesArray = array();

        $allCategories = $this->category_model->get_all(['parent_id' => $parent_id]);
        foreach($allCategories as $category) {
            $categoriesArray[$i] = $category;
            $categoriesArray[$i][] = $this->all_categories($category['id'], $categoriesArray);
        }
        return $categoriesArray;
    }

It sorts the categories pretty good - I get main cat and every sub- sub- sub- category of each children but I get them in one-dimensional array:

Array
(
    [0] => Array
        (
            [id] => 1
            [parent_id] => 0
            [title] => Shoes
            [description] => This is the shoes main category
            [image] => 
            [created_at] => 2016-02-18 14:22:56
            [updated_at] => 2016-02-18 14:22:56
            [active] => 
        )

    [1] => Array
        (
            [id] => 2
            [parent_id] => 1
            [title] => Sub-shoes
            [description] => This is sub-category of shoes
            [image] => 
            [created_at] => 2016-02-18 14:27:44
            [updated_at] => 2016-02-18 14:27:44
            [active] => 
        )

    [2] => Array
        (
            [id] => 8
            [parent_id] => 2
            [title] => Sub-sub-shoes
            [description] => This is sub-sub-shoes category
            [image] => 
            [created_at] => 2016-02-21 13:32:44
            [updated_at] => 2016-02-21 13:32:44
            [active] => 
        )

    [3] => Array
        (
            [id] => 5
            [parent_id] => 1
            [title] => Sub-shoes 2
            [description] => This is sub-shoes category after deleting the first of it's kind
            [image] => 
            [created_at] => 2016-02-18 14:40:33
            [updated_at] => 2016-02-18 14:40:33
            [active] => 
        )

    [4] => Array
        (
            [id] => 3
            [parent_id] => 0
            [title] => Dresses
            [description] => This is the main dress category
            [image] => 
            [created_at] => 2016-02-18 14:33:41
            [updated_at] => 2016-02-18 14:33:41
            [active] => 
        )

Can you show me a way so I can order them as each main category has index 'subs' which is array containing all its children and so on.

Best regards!

2

2 Answers

2
votes

I think you must use references :

public function all_categories($parent_id = 0, &$categoriesArray = array()) {
    $allCategories = $this->category_model->get_all(['parent_id' => $parent_id]);
    foreach($allCategories as $category) {
        $categoriesArray[$category['id']] = $category;
        $categoriesArray[$category['id']]['childs'] = array();
        $this->all_categories($category['id'], $categoriesArray[$category['id']]['childs']);
    }
}

$myCategoriesArray = array();
$this->all_categories(0, $myCategoriesArray);

NB : There may be a mistake, recursive loop are quiet hard just using your brain ^^

0
votes

The best solution would be to use objects instead of arrays to represent an recursive structure.

An simple solution four your problem would be to use an list, which stores refs to all possible parent nodes and add an children element to your array.

Doing this could result in something like the following

$ids = array();
$root = array(
    'id' => 0,
    'children' => array()
);
$ids[0] = &$root;

foreach ($data as $item) {
    $id = $item['id'];
    $parent_id = (int) $item['parent_id'];

    if (isset($ids[$parent_id])) {
        if (!isset($ids[$parent_id]['children'])) {
            $ids[$parent_id]['children'] = array();
        }
        $ids[$parent_id]['children'][] = &$item;
    }

    $ids[$id] = &$item;
    unset($item);
}

after running this code, $root contains your list in a tree like structure

array(2) {
  ["id"]=>
  int(0)
  ["children"]=>
  array(2) {
    [0]=>
    &array(3) {
      ["id"]=>
      int(1)
      ["parent_id"]=>
      int(0)
      ["children"]=>
      array(2) {
        [0]=>
        &array(3) {
          ["id"]=>
          int(2)
          ["parent_id"]=>
          int(1)
          ["children"]=>
          array(1) {
            [0]=>
            &array(2) {
              ["id"]=>
              int(8)
              ["parent_id"]=>
              int(2)
            }
          }
        }
        [1]=>
        &array(2) {
          ["id"]=>
          int(5)
          ["parent_id"]=>
          int(1)
        }
      }
    }
    [1]=>
    &array(2) {
      ["id"]=>
      int(3)
      ["parent_id"]=>
      int(0)
    }
  }
}