CodeIgniter Forums
Transform array for ul() function - Printable Version

+- CodeIgniter Forums (https://forum.codeigniter.com)
+-- Forum: Archived Discussions (https://forum.codeigniter.com/forumdisplay.php?fid=20)
+--- Forum: Archived Development & Programming (https://forum.codeigniter.com/forumdisplay.php?fid=23)
+--- Thread: Transform array for ul() function (/showthread.php?tid=37349)



Transform array for ul() function - El Forum - 01-06-2011

[eluser]babalooi[/eluser]
Hi.
Please help to transform array to multidimensional array for ul() or ol() function in HTML Helper.
It will be used for creating multi-level, hrizontal, dropdown navigation.
Thanks in advance.

Current array looks like this:

Code:
Array
(
    [0] => Array
        (
            [id] => 1
            [name] => Home
            [level] => 0
            [parent] => 0
        )

    [1] => Array
        (
            [id] => 29
            [name] => About us
            [level] => 1
            [parent] => 1
        )

    [2] => Array
        (
            [id] => 31
            [name] => Contact
            [level] => 1
            [parent] => 1
        )

    [3] => Array
        (
            [id] => 32
            [name] => Products
            [level] => 1
            [parent] => 1
        )

    [4] => Array
        (
            [id] => 34
            [name] => Mobile phones
            [level] => 2
            [parent] => 32
        )

    [5] => Array
        (
            [id] => 35
            [name] => Nokia
            [level] => 3
            [parent] => 34
        )

    [6] => Array
        (
            [id] => 38
            [name] => Samsung
            [level] => 3
            [parent] => 34
        )

    [7] => Array
        (
            [id] => 39
            [name] => Sony
            [level] => 3
            [parent] => 34
        )

    [8] => Array
        (
            [id] => 33
            [name] => Notebooks
            [level] => 2
            [parent] => 32
        )

    [9] => Array
        (
            [id] => 37
            [name] => Acer
            [level] => 3
            [parent] => 33
        )

    [10] => Array
        (
            [id] => 36
            [name] => Dell
            [level] => 3
            [parent] => 33
        )

)



Transform array for ul() function - El Forum - 01-06-2011

[eluser]Nick_MyShuitings[/eluser]
That's not so much a CodeIgniter questions as it is a PHP question... and its not even an easy PHP question... you need that array to look like this:

Code:
array(
            'colors' => array(
                                'red',
                                'blue',
                                'green'
                            ),
            'shapes' => array(
                                'round',
                                'square',
                                'circles' => array(
                                                    'ellipse',
                                                    'oval',
                                                    'sphere'
                                                    )
                            ),
            'moods'    => array(
                                'happy',
                                'upset' => array(
                                                    'defeated' => array(
                                                                        'dejected',
                                                                        'disheartened',
                                                                        'depressed'
                                                                        ),
                                                    'annoyed',
                                                    'cross',
                                                    'angry'
                                                )
                            )
            );

That is not going to be easy. I'd suggest changing your query so that it pulls each level seperately.

Then do a foreach over the 1st level and append the 2nd level when the parent matches the id of the 1st level.

Then do a deep foreach over the entire new array adding the 3rd level... all in all this sounds nasty... but its either that or do a recursive function, which I doubt you are up for since you didn't even provide an example of the ATTEMPTS that you made to solve your own problem.


Transform array for ul() function - El Forum - 01-06-2011

[eluser]babalooi[/eluser]
Nick, thanks for reply.

Yeah, I see, it's not so much Codeigniter question.

I needed some guidance for "how to".

I have tried so much "attempts" that it will be too much for this post.
I'll try your suggestion and change query.

I'm using the adjacency list model in database.
This is current function that gets result from db.
Code:
function get_children($parent, $level)
    {                            
        $this->db->where('parent', $parent);        
        $this->db->order_by('name', 'asc');
        $parents = $this->db->get('pages')->result_array();

        foreach ($parents as $parent) {
                                  
            $this->tree[] = array(
                'level' => $level,
                'name' => $parent['name'],
                'order' => $parent['order'],
                'parent' => $parent['parent'],
                'id' => $parent['id'],
                'template' => $parent['template'],
                'seo_name' => $parent['seo_name']
                );
                                  
            $this->get_children($parent['id'], $level+1);
        }
                  
        return $this->tree;
    }



Transform array for ul() function - El Forum - 01-06-2011

[eluser]Nick_MyShuitings[/eluser]
I have these functions in My_Model, they are used in all my tables of taxonomies and menus.

It is not finished yet, but the basic gist of it is the following:

1) you do not need to specify levels, it takes care of that itself
2) it is recursive so you can have infinite deep levels
3) it assumes the parent id is in the field tablename_id.

Example:

table menu
id|name|link|menu_id
1|projects|example.com|0
2|codeigniter|example.com/codeigniter|1

Here you see that the codeigniter project is a sub menu or menu item 1 which is "projects"

Here is the code:

Code:
/**
   * Get Head
   *
   * @return array
   * Use: takes a parent_id as an input and outputs that item
   */
  public function _get_head($id, $table = 0) {
    $table = ($table === 0)?$this->_table:$table;
    $this->db->where($table.'_id', $id);
    if ($this->condition_field) {
      $this->db->where($this->condition_field, '0');
    }
    $this->db->order_by($this->order_field, "asc");
    $query = $this->db->get($table);
    return $query->result_array();
  }
  /**
   * Get Items
   *
   * @return array
   * Use: takes a parent_id as an input and outputs all the children
   */
  public function & _get_items($id = 0, $table = 0) {
    $table = ($table === 0)?$this->_table:$table;
    $itemOverview =& $this->_get_head($id, $table);
    foreach ($itemOverview as $key => $val) {
      $item = $itemOverview[$key];
      if ($item['id'] != 0) {
        $childItems =& $this->_get_items($item['id'], $table);
      }
      if (!empty($childItems)) {
        $item['children'] =& $childItems;
      }
      $items[] = $item;
    }
    return $items;
  }



Transform array for ul() function - El Forum - 01-06-2011

[eluser]babalooi[/eluser]
I have this structure in DB table.

id name parent
1 home 0
2 about us 1
3 products 1
4 notebooks 3

Home is root page so it has no parent.

Nick, I have tried to use your functions.
Called function to test it, like this: _get_items(3, 'pages').
In DB table (above), this should list all children from products, or I didn't understand the purpose of function.
It ends up in infinite loop calling _get_items() and fills array until it runs out of memory.

Please consider that I'm more designer than programmer that's why I like to use Codeigniter with all his useful functions Smile.

Had to modify your functions.
Code:
public function _get_head($id, $table = 0)
{
    $table = ($table === 0)?$this->_table:$table;
    $this->db->where('id', $id);
    $this->db->order_by('name', "asc");
    $query = $this->db->get($table);

    return $query->result_array();
}

public function & _get_items($id = 0, $table = 0)
{
    $table = ($table === 0)?$this->_table:$table;
    $itemOverview =& $this->_get_head($id, $table);
        
     foreach ($itemOverview as $key => $val)
    {
        $item = $itemOverview[$key];
            
        if ($item['id'] != 0)
        {
            $childItems =& $this->_get_items($item['id'], $table); // this line causes crash
        }
            
        if (!empty($childItems))
        {
            $item['children'] =& $childItems;
        }
            
        $items[] = $item;
    }
        
    return $items;
        
}

Thanks.


Transform array for ul() function - El Forum - 01-06-2011

[eluser]Nick_MyShuitings[/eluser]
Hmm, one key is actually this line:

Code:
$this->db->where($table.'_id', $id);

Should be changed in your example to:

Code:
$this->db->where('parent', $id);

That was why you were getting an infinite loop, you were comparing id to id.

so, in this example:

id name parent
1 home 0
2 about us 1
3 products 1
4 notebooks 3

Table name: pages.

The call would be:

Code:
_get_items(0, ‘pages’).
would return the entire table nested since you called parent of 0
Code:
_get_items(1, ‘pages’).
should return everything that is a sub of home.

Lemme know if that still doesn't work... As is, this is a doozy of a problem that CI doesn't have a slick answer to. You either need to write nested foreachs or use a recursive function like this. Nested foreaches limits the levels of depth you can have. The recursive function is a nightmare to understand.

Nick


Transform array for ul() function - El Forum - 01-06-2011

[eluser]babalooi[/eluser]
Yep, works perfectly.

Now I have to figure out how to put that in list. I think it will be easier than old one.

Here are how functions look like now.
Code:
function get_parent($id)
{
    $this->db->select('id, name, parent');
    $this->db->where('parent', $id);
    $this->db->order_by('name', "asc");
    $query = $this->db->get('pages');
    
    return $query->result_array();
}

function & get_child($id)
{
    $page =& $this->get_parent($id);
    
    foreach ($page as $key => $value)
    {
        $link = $page[$key];
        
        if ($link['id'] != 0)
        {
            $children =& $this->get_child($link['id']);
        }
        
        if (!empty($children))
        {
            $link['children'] =& $children;
        }
        
        $links[] = $link;
    }
    
    return $links;
}

It generates array
Code:
Array
(
    [0] => Array
        (
            [id] => 1
            [name] => Home
            [parent] => 0
            [children] => Array
                (
                    [0] => Array
                        (
                            [id] => 29
                            [name] => About us
                            [parent] => 1
                        )

                    [1] => Array
                        (
                            [id] => 31
                            [name] => Contact
                            [parent] => 1
                        )

                    [2] => Array
                        (
                            [id] => 32
                            [name] => Products
                            [parent] => 1
                            [children] => Array
                                (
                                    [0] => Array
                                        (
                                            [id] => 34
                                            [name] => Mobile phones
                                            [parent] => 32
                                            [children] => Array
                                                (
                                                    [0] => Array
                                                        (
                                                            [id] => 35
                                                            [name] => Nokia
                                                            [parent] => 34
                                                        )

                                                    [1] => Array
                                                        (
                                                            [id] => 38
                                                            [name] => Samsung
                                                            [parent] => 34
                                                        )

                                                    [2] => Array
                                                        (
                                                            [id] => 39
                                                            [name] => Sony
                                                            [parent] => 34
                                                        )

                                                )

                                        )

                                    [1] => Array
                                        (
                                            [id] => 33
                                            [name] => Notebooks
                                            [parent] => 32
                                            [children] => Array
                                                (
                                                    [0] => Array
                                                        (
                                                            [id] => 37
                                                            [name] => Acer
                                                            [parent] => 33
                                                        )

                                                    [1] => Array
                                                        (
                                                            [id] => 36
                                                            [name] => Dell
                                                            [parent] => 33
                                                        )

                                                )

                                        )

                                )

                        )

                )

        )

)

Thanks Nick. If you ever come to Croatia you have beer Smile


Transform array for ul() function - El Forum - 01-06-2011

[eluser]Nick_MyShuitings[/eluser]
Woot. I will definitely take you up on that offer if I ever get over there. If not and you're ever in Argentina I'll let you buy me a beer here.

Lemme know if you run into any other snags.