简体   繁体   中英

php: Generate dynamic menu with CSS code from multidimensional array

I'm trying to mark the current requested page as active in my menu but something seems to go wrong... Me and my co-workers can't figure out what's going wrong... I've been trying to figure this one out for more than a week now, I've read what feels like dozens of questions and answers on this and other sites to no avail.

The one thing that really puzzles me is how the value of $page seems to change from a string to a number as you can tell with the debugging I've implemented.

This is the relevant code from index.php:

$pages = array('home','overons','onsteam','organisatie','diensten','aandeslag',
               'ictlab','eendagbij','opdrachtgevers','verwijzers',
               'trajectbegeleiding','contact');
if(in_array($_GET['p'], $pages)) {
    $content = $_GET['p'];
} else {
    $content = "home";
}
echo "<!-- content = ".$content." -->\n";
require($inc_path.'navbar'.$php_ext);

and the code from navbar.php:

 $menu = array (
            'home',
            'overons'       =>  array   (
                                        'onsteam',
                                        'organisatie'
                                        ),
            'diensten'      =>  array   (
                                        'aandeslag',
                                        'ictlab',
                                        'eendagbij'
                                        ),
            'opdrachtgevers',
            'verwijzers'    =>  array   (
                                        'trajectbegeleiding'
                                        ),
            'contact'
            );
$pagenames = array (
                'home'                  =>   'Home',
                'overons'               =>   'Over Ons',
                'onsteam'               =>   'Ons Team',
                'organisatie'           =>   'Organisatie',
                'diensten'              =>   'Diensten',
                'aandeslag'             =>   'Aan De Slag',
                'ictlab'                =>   'ICT Lab',
                'eendagbij'             =>   'Een dag bij',
                'opdrachtgevers'        =>   'Opdrachtgevers',
                'verwijzers'            =>   'Verwijzers',
                'trajectbegeleiding'    =>   'Traject begeleiding',
                'contact'               =>   'Contact'
                );
function MakeMenu($menu, $currentpage, $level = 0) {
    echo "<!-- MakeMenu0: currentpage = ".$currentpage." -->\n";
    global $pagenames;
    $ret = "";
    $indent = str_repeat(" ", $level * 2);
    if ($level!=0) {
        $ret .= "<!-- MakeMenu1: Level = ".$level." -->\n";
        $ret .= sprintf("%s<ul class=\"dropdown-menu\">\n", $indent);
    } else {
        $ret .= "<!-- MakeMenu2: Level = 0 -->\n";
        $ret .= sprintf("%s<ul class=\"nav navbar-nav\">\n", $indent);
    }
    $indent = str_repeat(" ", ++$level * 2);
    foreach ($menu as $page => $subpages) {
        if (!is_numeric($page)) {
            if ($page==$currentpage) {
                $ret .= "<!-- MakeMenu3: page (".$page.") = currentpage (".$currentpage.") -->\n";
                if (is_array($subpages)) {
                    $ret .= sprintf("%s<li class=\"active dropdowm\"><a href='?p=%s'>%s<span class='caret'></span></a>", $indent, $page, $pagenames[$page]);
                } else {
                    $ret .= sprintf("%s<li class=\"active\"><a href='?p=%s'>%s</a>", $indent, $page, $pagenames[$page]);
                }
            } else {
                $ret .= "<!-- MakeMenu4: page (".$page.") != currentpage (".$currentpage.") -->\n";
                if (is_array($subpages)) {
                    $ret .= sprintf("%s<li class=\"dropdown\"><a href='?p=%s'>%s<span class='caret'></span></a>", $indent, $page, $pagenames[$page]);
                } else {
                    $ret .= sprintf("%s<li><a href='?p=%s'>%s</a>", $indent, $page, $pagenames[$page]);
                }
            }
        }
        if (is_array($subpages)) {
            $ret .= "\n";
            $ret .= MakeMenu($subpages, $currentpage, $level + 1);
            $ret .= $indent;
        } else if (strcmp($page, $subpages)) {
            if ($page==$currentpage){
                $ret .= "<!-- MakeMenu5: page (".$page.") = currentpage (".$currentpage.") -->\n";
                $ret .= sprintf("%s<li class=\"active\"><a href='?p=%s'>%s</a>", $indent, $subpages, $pagenames[$subpages]);
            } else {
                $ret .= "<!-- MakeMenu6: page (".$page.") != currentpage (".$currentpage.") -->\n";
                $ret .= sprintf("%s<li><a href='?p=%s'>%s</a>", $indent, $subpages, $pagenames[$subpages]);
            }
        }
        $ret .= sprintf("</li>\n", $indent);
    }
    $indent = str_repeat(" ", --$level * 2);
    $ret .= sprintf("%s</ul>\n", $indent);
    return($ret);
}
echo MakeMenu($menu, $content);

And the very puzzeling output:

<!-- MakeMenu0: currentpage = overons -->
<!-- MakeMenu0: currentpage = overons -->
<!-- MakeMenu0: currentpage = overons -->
<!-- MakeMenu0: currentpage = overons -->
<!-- MakeMenu2: Level = 0 -->
<ul class="nav navbar-nav">
<!-- MakeMenu5: page (0) = currentpage (overons) -->
  <li class="active"><a href='?p=home'>Home</a></li>
<!-- MakeMenu3: page (overons) = currentpage (overons) -->
  <li class="active dropdowm"><a href='?p=overons'>Over Ons<span class='caret'></span></a>
<!-- MakeMenu1: Level = 2 -->
    <ul class="dropdown-menu">
<!-- MakeMenu5: page (0) = currentpage (overons) -->
      <li class="active"><a href='?p=onsteam'>Ons Team</a></li>
<!-- MakeMenu6: page (1) != currentpage (overons) -->
      <li><a href='?p=organisatie'>Organisatie</a></li>
    </ul>
  </li>
<!-- MakeMenu4: page (diensten) != currentpage (overons) -->
  <li class="dropdown"><a href='?p=diensten'>Diensten<span class='caret'></span></a>
<!-- MakeMenu1: Level = 2 -->
    <ul class="dropdown-menu">
<!-- MakeMenu5: page (0) = currentpage (overons) -->
      <li class="active"><a href='?p=aandeslag'>Aan De Slag</a></li>
<!-- MakeMenu6: page (1) != currentpage (overons) -->
      <li><a href='?p=ictlab'>ICT Lab</a></li>
<!-- MakeMenu6: page (2) != currentpage (overons) -->
      <li><a href='?p=eendagbij'>Een dag bij</a></li>
    </ul>
  </li>
<!-- MakeMenu6: page (1) != currentpage (overons) -->
  <li><a href='?p=opdrachtgevers'>Opdrachtgevers</a></li>
<!-- MakeMenu4: page (verwijzers) != currentpage (overons) -->
  <li class="dropdown"><a href='?p=verwijzers'>Verwijzers<span class='caret'></span></a>
<!-- MakeMenu1: Level = 2 -->
    <ul class="dropdown-menu">
<!-- MakeMenu5: page (0) = currentpage (overons) -->
      <li class="active"><a href='?p=trajectbegeleiding'>Traject begeleiding</a></li>
    </ul>
  </li>
<!-- MakeMenu6: page (2) != currentpage (overons) -->
  <li><a href='?p=contact'>Contact</a></li>
</ul>

Well regarding puzzling behavior:

The one thing that really puzzles me is how the value of $page seems to change from a string to a number as you can tell with the debugging I've implemented.

If you look closely at this line:

foreach ($menu as $page => $subpages) {

you will see that key of an array is assigned to $page . From your array:

$menu = array (
    'home',
    'overons' => array(
        'onsteam',
        'organisatie'
    ),
    'diensten' =>  array(
        'aandeslag',
        'ictlab',
        'eendagbij'
    ),
    'opdrachtgevers',
    'verwijzers' => array(
        'trajectbegeleiding'
    ),
    'contact'
);

we can see that some of pages are keys, and some are values. That is why you have sometimes pages names and sometimes array indexes.

You can define your array as following to prevent this behavior:

$menu = [
    'home' => null,
    'overons' => [
        'onsteam' => null,
        'organisatie' => null
    ],
    'diensten' =>  [
        'aandeslag' => null,
        'ictlab' => null,
        'eendagbij' => null
    ],
    'opdrachtgevers' => null,
    'verwijzers' => [
        'trajectbegeleiding' => null
    ],
    'contact' => null
];

Going further you have a really complicated recursive function. I would suggest using PHP Iterators . In particular RecursiveArrayIterator alongside with RecursiveIteratorIterator , that can be extended like this:

class UlRecursiveIteratorIterator extends RecursiveIteratorIterator
{
    public function beginIteration()
    {
        echo '<ul class="nav navbar-nav">', PHP_EOL;    
    }

    public function endIteration()
    {
        echo '</ul>', PHP_EOL;
    }

    public function beginChildren()
    {
        echo str_repeat('    ', $this->getDepth() + 1), '<ul class="dropdown-menu">', PHP_EOL;
    }

    public function endChildren()
    {
        echo str_repeat('    ', $this->getDepth() + 1), '</ul>', PHP_EOL;
        echo str_repeat('    ', $this->getDepth()), '</li>', PHP_EOL;   
    }
}

Having this iterator, your function can be refactored to one simple foreach loop:

$iterator = new RecursiveArrayIterator($menu);
$iterator = new UlRecursiveIteratorIterator(
    $iterator,
    RecursiveIteratorIterator::SELF_FIRST
);

foreach ($iterator as $page => $_) {
    $active = false;

    // Used for pritty print only. Remove in production.
    $depth = $iterator->getDepth();
    $line = str_repeat('    ', ($depth + 1) + ($depth === 0 ? 0 : 1));

    if ($page === $content) {
        $active = true;
    }

    $class = $active ? 'active' : '';

    if ($iterator->callHasChildren()) {
        $line .= "<li class=\"$class dropdown\"><a href='?p=$page'>{$pagenames[$page]}<span class='caret'></span></a>";
    } else {
        $line .= "<li class=\"$class\"><a href='?p=$page'>{$pagenames[$page]}</a>";   
    }

    echo $line, PHP_EOL;
}

Here is the demo .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM