Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using recursion to build navigation

I'm building navigation for a site and for the life of me I can't figure out recursion. I have all my data stored via MySQL using this design:

enter image description here

I've read several links on how recursion works and I must be slow because it's difficult for me to grasp. I've tried to write something and I know it is not even close to what I really need, but it's a start:

PDO

public function viewCategories()
{
    $viewSQL = "SELECT * FROM categories";  
    try
    {
        $pdo = new PDO('mysql:host=localhost;dbname=store','root','');
        $pdo->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
        $categoryVIEW = $pdo->prepare($viewSQL);
        $categoryVIEW->execute();
        $array = $categoryVIEW->fetchAll(PDO::FETCH_ASSOC);
        $categoryVIEW->closeCursor();
        $json = json_encode($array);
        return $json;
    }
    catch(PDOexception $e)
    {
        return $e->getMessage();
        exit();
    }
}

Recursion

$return = json_decode($category->viewCategories(),true);

function buildNavigation($json)
{
    foreach($json as $item)
    {
        if($item['category_id'] === $item['parent'])
        {
            print('<li>'.$item['category_name'].'</li>');
            if($item['category_id'] === $item['parent'])
            {
                print('<li>match'.$item['category_name'].'</li>');
                buildNavigation($json);
            }
        }
}
buildNavigation($return);

as expected this will never enter the condition. I did try to figure this out on my own since this is a good thing to have knowledge of, but I guess it's beyond my mental capacity :(

Thanks for having a look :)

UPDATE

I know this has been answered already, but is there a way I can do this to build an associative array? I have been playing around with a function that ALMOST works for me that I got from HERE, but it adds an extra array that I do NOT want.

Method

private function buildCategories($array,$parent)
{
    $result = array();
    foreach($array as $row)
    {
        if($row['parent'] == $parent)
        {
            $result[$row['category_name']] = $this->buildCategories($array,$row['category_id']);
        }
    }
    return $result;
}
$json = json_encode($this->buildCategories($array,NULL));
return $json;

I want this:

{"reloading":{"components","presses and dies","tumblers & scales","tools & accessories","shotshell reloading"}

but what I get is this:

{"reloading":{"components":[],"presses and dies":[],"tumblers & scales":[],"tools & accessories":[],"shotshell reloading":[]}
like image 784
Mike Avatar asked Oct 21 '12 21:10

Mike


1 Answers

Here's an example with recursion.

function buildNavigation($items, $parent = NULL)
{
    $hasChildren = false;
    $outputHtml = '<ul>%s</ul>';
    $childrenHtml = '';

    foreach($items as $item)
    {
        if ($item['parent'] == $parent) {
            $hasChildren = true;
            $childrenHtml .= '<li>'.$item['category_name'];         
            $childrenHtml .= buildNavigation($items, $item['category_id']);         
            $childrenHtml .= '</li>';           
        }
    }

    // Without children, we do not need the <ul> tag.
    if (!$hasChildren) {
        $outputHtml = '';
    }

    // Returns the HTML
    return sprintf($outputHtml, $childrenHtml);
}

print buildNavigation($items);

That script produces the following output :

<ul>
    <li>Menu 1</li>
    <li>Menu 2
        <ul>
            <li>Sub Menu 2.1</li>
            <li>Sub Menu 2.2</li>
            <li>Sub Menu 2.3
                <ul>
                    <li>Sub Menu 2.2.1</li>
                    <li>Sub Menu 2.2.2</li>
                    <li>Sub Menu 2.2.3</li>
                </ul>
            </li>
        </ul>
    </li>
    <li>Menu 3</li>
</ul>
like image 153
Maxime Morin Avatar answered Sep 29 '22 16:09

Maxime Morin