0

EDIT

I'm trying to create a little CMS for testing purposes. I've setup a class that creates a navigation with nested elements depending on an array of which the output looks like this:

Array
(
    [0] => Array
        (
            [name] => Home
            [link] => 
        )

    [1] => Array
        (
            [name] => About us
            [link] => about
            [children] => Array
                (
                    [0] => Array
                        (
                            [name] => Team
                            [link] => team
                        )

                    [1] => Array
                        (
                            [name] => History
                            [link] => history
                        )

                )

        )

    [2] => Array
        (
            [name] => Contact
            [link] => contact
        )

)

It works quite good so far but what I finally need is an array with unlimited nesting possibilities. Something like this:

Array
(
    [0] => Array
        (
            [name] => Home
            [link] => 
        )

    [1] => Array
        (
            [name] => About us
            [link] => about
            [children] => Array
                (
                    [0] => Array
                        (
                            [name] => Team
                            [link] => team
                        )

                    [1] => Array
                        (
                            [name] => History
                            [link] => history,
                            [children] => Array
                            (
                                [name] => Pictures
                                [link] => pictures
                            )
                        )

                )

        )

    [2] => Array
        (
            [name] => Contact
            [link] => contact
        )

)

I'm using the following PHP script to populate the array with data from the db:

/**
 * Loops through the children of a page and adds them accordingly to the pages array
 *
 * @param array $parent
 * @param array $children
 */
private function getChildrenPages($parent, $children) {
    $subpages = array();

    foreach ($children as $child) {
        array_push($subpages, array(
            'name' => $child['name'],
            'link' => $child['link']
        ));
    }

    array_push($this->pages, array(
        'name' => $parent['name'],
        'link' => $parent['link'],
        'children' => $subpages
    ));
}

/**
 * @return array Returns an multidimensional associative array with all pages
 */
private function fetchPages() {
    // Prevent multiple db fetches
    if(!count($this->pages)){
        $all_pages = $this->db->get('pages');

        for ($i=0; $i < count($all_pages); $i++) {
            $parent = $all_pages[$i];

            // Get children of current item
            $this->db->where('parent_id', $parent['id']);
            $children = $this->db->get('pages');

            //
            if(count($children)) {
                $this->getChildrenPages($parent, $children);
            }

            if (!$parent['parent_id'] && !count($children)) {
                // Append current item without children to pages array
                array_push($this->pages, array(
                    'name' => $parent['name'],
                    'link' => $parent['link']
                ));
            }
        }
    }
}

This works for 1st and 2nd level items. But how to handle further level items? I guess I'd have to transform my getChildrenPages() function to a recursive function but no clue how to make that in this case. Any suggestions?

3
  • It's usually far easier to store hierarchies like this by storing a single parent_id field per row rather than multiple ids in a children field like you have here. Then you can actually JOIN on meaningful data instead of having to parse strings. Commented Mar 27, 2014 at 17:10
  • @Sammitch Could you give me an example? I thought JOIN is used for multiple tables as for two rows? Commented Mar 27, 2014 at 17:20
  • 1
    There's no rule against joining a table to itself. Example: I don't know why fiddle isn't showing the right side of that join, but trust me, it's there. :I Commented Mar 27, 2014 at 17:59

1 Answer 1

1

Okay, I think you're on the right track. I've done something similar to this in the past, except instead of the parents listing the children, I had the children list the parents. Small difference semantically, I suppose, but it will make things a lot easier for you.

List all of the items that do not have a parent. These will be your main navigational items. For each item that you display, check to see if any rows are claiming this item as their parent. If so, then go ahead and list them out under them. That's all there is to it!

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

4 Comments

Thank you for your suggestion. How would you deal with a 3 level menu? So let's say if the Team page would contain another subpage?
All I did was to set the parent to be the id of the 2nd level child row. So imagine if a, b, c, were the menu items and aa & bb had their parents listed as b. Then you can just list aaa & bbb as having the parent bb.
Sounds reasonable. Could you maybe show me some of your code?
I adapted my code and database scheme and rewrote my question. Please have a look.

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.