Programmieren > Sprachen > PHP > Just-PHP

Navigation für JustPHP

Features einer automatischen Navigation

Die Navigations-Struktur in der linken Spalte von JustPHP wird händisch in top.php angelegt. Dies ist für den Anfang und bei wenigen Seiten, die so verlinkt werden durchaus ausreichend. Sobald die Anzahl der Seiten und die Verschachtelungstiefe ein gewisses Ausmass erreichen, ergeben sich mehrere Probleme. Einige davon sind.

Ich möchte deshalb hier eine dynamische Navigation entwickeln, die zwar immer noch sehr einfach ist, aber doch schon deutlich mehr Features enthält, wie eine rein statische Navigation.

Features:

Damit die nun dargestellte Navigation funktioniert müssen die Unterseiten auf eine bestimmte Art angelegt werden. Am einfachsten erkläre ich das an einem Beispiel.

Will ich eine neue Seite mit dem Titel Testseite anlegen, kopiere ich die Datei template.php benenne die Kopie um in testseite.php und lege sie in dasselbe Verzeichnis wie die index.php. Will ich eine Unterseite zu dieser Seite anlegen erzeuge ich im selben Verzeichnis ein Unterverzeichnis mit dem namen testseite. In diese lege ich Unterseiten von testseite.php genauso an, wie die Testseite. Wenn ich Material in die Testseite einbinde (Bilder, Download-Material, ...) kommt dies ebenfalss in das Unterverzeichnis testseite. Auf diese Weise bekomme ich eine übersichtliche Struktur, die ich in der folgenden Navigations-Klasse verwenden kann, um die dynamische Navigation aufzubauen.

top.php

Damit die automatische Navigation funktioniert, muss die Datei top.php, die ja bisher die statische Navigation enthält, geändert werden. Die neue Datei enthält die Einbindung der Klasse Navigation.php sowie deren Verwendung, um die Navigation zu erzeugen. Wie die Klasse Navigation funktioniert, wird im nächsten Kapitel erklärt.

Wenn man das Original zum Vergleich sieht, kann man gut die Veränderungen sehen. Oben wird zuerst die Navigations-Klasse eingebunden, damit sie im späteren Verlauf verwendet werden kann. Im HTML-Code unten ist die statische Navigation durch die Aufrufe der Navigations-Funktionen ersetzt worden, die die Navigation erzeugen.

Bevor ein Navigations-Objekt erzeugt werden kann, muss noch die Navigations-Struktur als PHP-Array definiert werden. Ich hätte zwar auch eine Funktion schreiben können, die die Verzeichnisstruktur automatisch absucht und daraus den Navigations-Baum erzeugt. Aus verschiedenen Gründen habe ich mich gegen diese Möglichkeit entschieden.

Aus diesen und anderen Gründen habe ich mich dazu entschieden, die Struktur manuell zu definieren. Die Struktur ist dabei möglichst einfach gehalten und folgendermassen aufgebaut.

<!DOCTYPE html>
<?php
date_default_timezone_set('Europe/Berlin');
require_once("classes/load.php");
$navigation = [
    ["label" => "Programmieren", "url" => "programmieren.php", "children" => [
            ["label" => "Konzepte", "url" => "konzepte.php"],
            ["label" => "Sprachen", "url" => "sprachen.php"],
            ["label" => "Werkzeuge", "url" => "werkzeuge.php", "children" => [
                    ["label" => "Git", "url" => "git.php"],
                ],
            ],
        ],
    ],
    ["label" => "Betriebssysteme", "url" => "betriebssysteme.php"],
];
$nav = new Navigation($navigation);
?>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <script type='text/javascript' src='/js/jquery.min.js'></script>
        <script src="/js/jqplot/jquery.jqplot.min.js"></script>
        <script type='text/javascript' src='/js/erichweigand.js'></script>
        <title><?php echo $title ? $title : 'Herzlich Willkomen bei Erich Weigand'; ?></title>
        <link rel="stylesheet" type="text/css" href="/js/jqplot/jquery.jqplot.min.css" />
        <link rel='stylesheet' id='ewstyle-css'  href='/css/erichweigand.css' type='text/css' media='all' />
    </head> 
    <body>
        <div class="navbar-top">
            <a class="navbar-brand" href="/">Herzlich Willkommen</a>
            <ul class="navbar-nav">
                <li><a href="/programmieren.php">Programmieren</a> | </li>
                <li><a href="/betriebssysteme.php">Betriebssysteme</a></li>
            </ul>
        </div>
        <div class="container" role="main">
            <div class="col-nav">
                <?php echo $nav->createBreadCrumb(); ?>
                <?php echo $nav->createNavigation(); ?>
            </div>
            <div class="col-content">

classes/Navigation.php

Diese Datei muss mit der Datei load.php eingebunden werden.

<?php

class Navigation {

    private $breadcrumb = [];
    private $maxDepth = 2;
    private $navigation;
    private $pageUrl;
    private $subNavigation;

    /**
     * Konstruktor erhält die Datenstruktur für die Navigation
     */
    public function __construct($navigation) {
        $this->pageUrl = $_SERVER["SCRIPT_NAME"];
        $this->navigation = $this->initNavigation($navigation, "/", []);
        // Wurde keine SubNavigation gefunden stelle die ganze Navigation dar.
        if(!$this->subNavigation) {
            $this->subNavigation = $this->navigation;
        }
    }

    /**
     * Diese Funktion ersetzt die URL im Navigations-Array durch die vollständige URL und erstellt
     * ein Array für die Brotkrumen-Navigation.
     */
    private function initNavigation($navigation, $basePath, $breadcrumb) {
        foreach ($navigation as $index => $item) {
            // Wenn kein externer link angegeben, interner Link basteln.
            if (!preg_match('/^http/', $item["url"])) {
                $item["url"] = $basePath . $item["url"];
            }
            // Dies ist die aktuelle Seite, also gesammelte Brotkrumen und Subnavigation merken.
            if ($this->pageUrl == $item["url"]) {
                $this->subNavigation = &$navigation;
                $this->breadcrumb = $breadcrumb;
            }
            if (isset($item["children"])) {
                $childBase = preg_replace('/.php$/', '', $item["url"]) . '/';
                $childBc = $breadcrumb;
                $childBc[] = ["url" => $item["url"], "label" => $item["label"]];
                $item["children"] = $this->initNavigation($item["children"], $childBase, $childBc);
            }
            $navigation[$index] = $item;
        }
        return $navigation;
    }

    /**
     * Baut einen String auf, der die HTML-Struktur der Navigation enthält.
     * Wird rekursiv aufgerufen, um einen beliebig tiefen Baum darstellen zu können.
     * 
     * @param array|null $navigation enthält den Teilbaum, der bei diesem Aufruf gerendert wird.
     * @param int $depth aktuelle tiefe der Rekursion
     * @return string der fertig gerenderte HTML-Baum
     */
    public function createNavigation($navigation = null, $depth = 0) {
        // kein Wert in $navigation -> Das Rendering wird gerade begonnen -> zuerst die benötigte Baumstruktur besorgen.
        if (!$navigation) {
            $navigation = $this->subNavigation;
        }
        $liTagList = "";
        foreach ($navigation as $item) {
            $liTag = '<a href="' . $item["url"] . '">' . $item["label"] . "</a>\n";
            // Für die aktuelle Seite keinen Link.
            if ($this->pageUrl == $item["url"]) {
                $liTag = $item["label"];
            }
            if (isset($item["children"]) && ($this->maxDepth > $depth)) {
                $liTag .= $this->createNavigation($item["children"], $depth + 1);
            }
            $liTagList .= "<li>\n" . $liTag . "</li>\n";
        }
        return "<ul>\n" . $liTagList . "</ul>\n";
    }

    public function createBreadCrumb() {
        $breadcrumb = [];
        foreach ($this->breadcrumb as $item) {
            $breadcrumb[] = '<a href="' . $item["url"] . '">' . $item["label"] . "</a>";
        }
        return implode(" &gt; ", $breadcrumb);
    }

}