views:

64

answers:

2

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  A: 

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.

Timwi
Yes, thats what I want I think.
purple
+1  A: 

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.

fidr