1

I have the following code (I know that this code is not optimized but it's not for discussion):

function select_categories($cat_id)
{
    $this->db = ORM::factory('category')
            ->where('parent', '=', $cat_id)
            ->find_all();

    foreach ($this->db as $num => $category)
    {
        if($category->parent == 0)
        {
            $this->tmp[$category->parent][$category->id] = array();
        }
        else {
            $this->tmp[$category->parent][$category->id] = array();
        }

        $this->select_categories($category->id);
    }

    return $this->tmp;
}

Function returns this array:

array(3) (
    0 => array(2) (
        1 => array(0) 
        2 => array(0) 
    )
    2 => array(1) (
        3 => array(0) 
    )
    3 => array(2) (
        4 => array(0) 
        5 => array(0) 
    )
)

But how should I change the code

else {
    $this->tmp[$category->parent][$category->id] = array();
        // ^^^^^^^^^^^^^^^^^^^^^^ (this bit)
}

To merge array[3] to array[2][3] for example (because array[3] is a subdirectory of array[2] and array[2] is a subdirectory of array[0][2]), so, I need to make this (when I don't know the level of subdirectories):

array (
    0 => array (
        1 => array 
        2 => array (
                    3 => array (
                                4 => array
                                5 => array
                                ) 
                    ) 
    ) 
)
2
  • Im not quite sure how you determine which is supposed to be a subdirectory of which? Can you explain this a bit more? Commented Aug 21, 2010 at 23:35
  • Yes, sure. I have the table with columns: 'id', 'name', 'parent'. Also there are some another columns but we not interested in this. So, 'parent' is the column wich contains 'id' of the parent category for current category and is zero if category is root. Commented Aug 22, 2010 at 10:09

2 Answers 2

2

A long time ago I wrote some code to do this in PHP. It takes a list of entities (in your case, categories) and returns a structure where those entities are arranged in a tree. However, it uses associative arrays instead of objects; it assumes that the “parent” ID is stored in one of the associative array entries. I’m sure that you can adapt this to your needs.

function make_tree_structure ($nontree, $parent_field)
{
    $parent_to_children = array();
    $root_elements = array();

    foreach ($nontree as $id => $elem) {
        if (array_key_exists ($elem[$parent_field], $nontree))
            $parent_to_children [ $elem[$parent_field] ][] = $id;
        else
            $root_elements[] = $id;
    }

    $result = array();
    while (count ($root_elements)) {
        $id = array_shift ($root_elements);
        $result [ $id ] = make_tree_structure_recurse ($id, $parent_to_children, $nontree);
    }
    return $result;
}

function make_tree_structure_recurse ($id, &$parent_to_children, &$nontree)
{
    $ret = $nontree [ $id ];
    if (array_key_exists ($id, $parent_to_children)) {
        $list_of_children = $parent_to_children [ $id ];
        unset ($parent_to_children[$id]);
        while (count ($list_of_children)) {
            $child = array_shift ($list_of_children);
            $ret['children'][$child] = make_tree_structure_recurse ($child, $parent_to_children, $nontree);
        }
    }
    return $ret;
}

To see what this does, first try running it on a structure like this:

var $data = array (
    0 => array('Name' => 'Kenny'),
    1 => array('Name' => 'Lilo', 'Parent' => 0),
    2 => array('Name' => 'Adrian', 'Parent' => 1)
    3 => array('Name' => 'Mark', 'Parent' => 1)
);

var $tree = make_tree_structure($data, 'Parent');

If I’m not mistaken, you should get something like this out: (the “Parent” key would still be there, but I’m leaving it out for clarity)

array (
    0 => array('Name' => 'Kenny', 'children' => array (
        1 => array('Name' => 'Lilo', 'children' => array (
            2 => array('Name' => 'Adrian')
            3 => array('Name' => 'Mark')
        )
    )
)

Examine the code to see how it does this. Once you understand how this works, you can tweak it to work with your particular data.

Sign up to request clarification or add additional context in comments.

1 Comment

Yes, thats what I want I think.
1

Assuming you dont want any data/children tags in your array:

foreach ($this->db as $num => $category)
{
    // save the data to the array
    $this->tmp[$category->id] = array();

    // save a reference to this item in the parent array
    $this->tmp[$category->parent][$category->id] = &$this->tmp[$category->id];

    $this->select_categories($category->id);
}

// the tree is at index $cat_id
return $this->tmp[$cat_id];

If you just need to retrieve the full tree out of the database, you can even simplify your query (get all records at once) and remove the recursive call in this function. You will need an extra check that will only set the $this->tmp[$catagory->id] when it does not exist and else it should merge the data with the existing data.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.