Vorschau Zend Framework 1.8: Navigation

Seit gestern ist die Beta der 1.8 veröffentlicht. Eine weitere neue, tolle Änderung ist Zend_Navigation, eine Komponente, die Entwicklern bei der Zusammenstellung einer Navigation maßgeblich unterstützt. Sie ist allerdings recht umfangreich, weswegen ich sie hier nur anreißen werde.

Eine Navigation

Eine Navigation ist ein Abbild der Struktur einer Seite, so wie sie sich der Entwickler vorgestellt hat. Querverweise zwischen Seiten oder Teilen von Seiten untereinander bleiben dabei unberücksichtigt, weswegen eine einfache Baumstruktur übrig bleibt. Jede Seite besitzt eine Ziel, ein Titel und diverse Eigenschaften, die sich später mehr oder weniger direkt im HTML-Quelltext widerspiegeln. Die ersten beiden Punkte sind eindeutig und entsprechen ziemlich genau den Mindestanforderungen für ein HTML-Link.

<a href="/path/to/page">title</a>

Meist wird zusätzlich noch zwischen internen (Seiten innerhalb einer Anwendung) und externen Links (Seiten ausserhalb der eigenen Anwendung) unterscheiden. Der Sinn dahinter ist, dass innerhalb der Navigation eine Seite als “gerade betrachtet” (aktiv) markiert und in der Darstellung darauf reagiert werden kann.
Die Darstellung ist unabhängig von der eigentlichen Struktur. Es gibt verschiedene Varianten, verbreitet sind

  • Menü: Die Darstellung, wie sie sich der Entwickler vorstellt, um ausgehend von einer Seite zu anderen Seiten zu gelangen, meist dargestellt durch eine Liste. Der einfachste Fall ist die Darstellung der gesamten Baumstruktur, wird aber oft vereinfacht.
  • Breadcrumb: Die Assoziation mit dem Märchen ist gewollt ;) . Dargestellt wird der Pfad vom Ausgangspunkt bis zur aktuellen Seite, was auch wieder auf verschiedene Arten eingeschränkt werden kann. Der Pfad muss nicht zwangsläufig derjenige sein, den man bis zur Seite wirklich eingeschlagen hat.
  • Beziehungen: Darstellung der Beziehung einer Seite zu anderen Seite, meist in Form von Links wie “next”, “prev”, “up”, usw. [2]
  • Sitemap: Eine Darstellung der Baumstruktur ohne “künstlerische Elemente”, meist als XML [1] und vorwiegend gedacht für Suchmaschinen-Bots oder ähnlichen Systemen.

In Zend_Navigation ist Struktur und Darstellung ebenso unabhängig, für Letztere sorgen diverse View-Helfer, für die Struktur sehen sich die Zend_Navigation_*-Klassen verantwortlich. Wie gehabt werde ich bei allen Klassen und Interfaces auf ein führendes Zend_Navigation verzichten, solange klar ist, was damit gemeint ist.

Die Umsetzung erfolgt dabei direkt: Eine Seite ist eine Page und mehrere zusammengehörige Seiten kommen in ein Container. Eine Page ist dabei selbst ein Container und kann somit untergeordnete Seiten aufnehmen.

Von Seiten und Containern

Eine Klasse, die von Zend_Navigation_Page erbt, kann als Seite genutzt werden. Zwei solcher Klassen sind bereits vordefiniert und reichen für die Mehrheit aller Fälle aus. Page_Uri bekommt eine “normale” Adresse und stellt diese so da. Dies ist gedacht für externe Links. Page_Mvc ist gedacht für interne Links (und bei Verwendung der MVC-Komponente) und erlaubt es Zend_Navigation die aktuelle Position in der Navigation zu bestimmen.

Als eine konkrete Implementierung des Klasse Zend_Navigation_Container gibt es (ausgenommen der Page-Klassen) nur noch Zend_Navigation selbst. Sie soll vorallen die Ausgangsseiten der Navigation aufnehmen und bietet ansonsten keine zusätzlichen Möglichkeiten. Grundsätzlich ist es möglich die gesamte (Unter-)Struktur bereits zur Instanzierung über ein Zend_Config-Objekt oder ein Array vorzunehmen, bei Page ist dies sogar Pflicht.

Für alle Seiten gibt es eine ganze Menge Möglichkeiten sie zu beschreiben, wovon zunächst keine Pflicht ist [3]. Zusätzlich dazu ist bei jeder Page-Klasse jede beliebige (andere) Eigenschaft setzbar, die aber nicht von sich aus ausgewertet werden. Auf alle wird bei einem (Page-)Objekt über set() bzw get(), über entsprechende Setter- und Getter-Methode, oder über “Magic Properties” zugegriffen. Mehr der ZF-Stil ist allerdings die Übergabe eines assoziativen Arrays oder Zend_Config-Objektes an setOptions(), oder die Übergabe als Konstruktor-Argument, der das Array oder Objekt dann an setOptions() weiter reicht.

Allen Seiten kann eine Eigenschaft pages zugewiesen werden, die ein asoziatives Array aller Unterseiten enthält, der Schlüssel ist dabei ein interner Bezeichner. Der Wert jeder Seite ist entweder ein Objekt von Page, oder (wieder mehr ZF-Stil) wieder ein asoziatives Array Config-Objekt, welches dem Konstruktor der Seiten-Klasse übergeben wird. Hier ist aber noch zwingend der Schlüssel type erforderlich, der den (gekürzten) Klassennamen der Seite enthält [4], also standardmässig “Mvc” oder “Uri”. Die Klasse Zend_Navigation wird ein solches Array direkt zugewiesen. Auf diese Weise lässt sich die gesamte Struktur in einem Rutsch erstellen.

$nav = new Zend_Navigation (array (
  'ebene1seite1' => array (
    'label' => 'Text1-1',
    'type' => 'uri',
    'uri' => 'http://example.com',
    'pages' => array (
      'ebene2seite1' => $ebene2seite1Def
    ),
  'ebene1seite2' => $ebene1seite2Def
  )
));

Ich hab das mal abgekürzt, weil sich der gesamte Aufbau sowieso wiederholt und irgendwann an Übersichtlichkeit einbüßt. Interessanter wird es sowieso sein stattdessen ein Config zu übergeben. Weil es vom Aufbau genau so aussieht, nur eben als Ini oder Xml, findet sich ein vergleichbares Beispiel weiter unten. Um nun die Navigation noch per View-Helper ausgeben zu können, muss man das Objekt dem Navigation noch bekannt machen.

$view->getHelper('navigation')->navigation($nav);

Bei mehreren Navigationen lässt sich auf diese Weise auch das Objekt, was verwendet wird, ändern. Auf die View-Helfer will ich auch nicht weiter eingehen. Im einfachsten Fall ruft man im View-Skript den Helper für die gewünschte Darstellung auf

echo $this->navigation()->menu(); 

Kombinationsspiel

Nun kann man auf die Idee kommen, dass sich der Aufbau der Navigation gut als Bootstrap umsetzen lässt und tatsächlich findet sich eine Klasse Zend_Application_Resource_Navigation. Wen es bis jetzt zuviel war, wird jetzt sicher überraschend sein, wie einfach man nun die Navigation umsetzen kann. Der Aufbau für die Konfiguration, die die Resource auswertet, sieht genauso aus, wie die Konstruktor-Parameter, die oberen Ebene wird allerdings noch einmal in ein pages geschachtelt [5].

<config>
  <section>
    <resources>
      <navigation>
        <pages>

          <seite1>
            <type>uri</type>
            <uri>example.com</uri>
          </seite1>
          <seite2>
            <type>mvc</type>
            <controller>another</controller>
            <pages>
              <unterseite1>
                <type>mvc</type>
                <controller>another</controller>
                <action>alsoAnother</action>
              </unterseite1>
            </pages>
          </seite2>

        </pages>
      </navigation>
    </resources>
  </section>
</config>

Ich habe hier XML gewählt, weil INI noch unübersichtlicher ist ;) Letzten Endes war es das auch schon. Hat man auf diese Weise seine Navigation zusammen gebaut, wird sie von der Bootstrap erstellt und dem View-Helfer übergeben. Im entsprechenden View-Skript nur noch den entsprechenden Helfer aufrufen, auch gerne mehrere oder mehrfach.

Hier ist man allerdings auf eine einzelne Navigation beschränkt. Möchte man mehrere einsetzen, muss man sich was ausdenken ;)

Und sonst

Des Weiteren gibt es noch Möglichkeiten die Navigation übersetzen zu lassen, oder die Anzeige einzelner Links über ACL zu steuern. Beides sind Features der View-Helfer und dort beschrieben.

Und Tschüß

Tschüß,
Sebastian Krebs[aka]KingCrunch

[1] http://www.sitemaps.org/protocol.php
[2] Dem Link kann auch die Beziehung zu dem Verweis mitgeilt werden (SelfHTML). Ab HTML4 gibt es zudem die Möglichkeit solche Links bereits (unsichtbar) im HTML-Kopf einzubetten (Document relationships: the LINK element, Link Types), die von den verschiedenen Browser mehr oder weniger konsequent ausgewertet werden. Zum Beispiel lädt FireFox die Seiten, die mit “next” verknüpft sind, bereits vor. Eine Möglichkeit zur Darstellung bietet zum Beispiel Link Widget (FireFox Addon), der allerdings auch rät, wenn die entsprechenden link-Tags im HTML-Kopf fehlt.
[3] Weiter Eigenschaften für alle Page-Klassen: http://framework.zend.com/manual/de/zend.navigation.pages.html#zend.navigation.pages.common
Und für Page_Mvc: http://framework.zend.com/manual/de/zend.navigation.pages.html#zend.navigation.pages.mvc
[4] Zend_Navigation sieht zur Zeit keine anderen Seitentypen vor, die über Zend_Navigation_Page::factory() instanziert werden können.
[5] Es sind noch weitere Schlüssel für Optionen möglich, die nicht mit Seiten verwechselt werden dürfen.


Comments

3 responses to “Vorschau Zend Framework 1.8: Navigation”

Leave your response
  1. [...] Navigation lesenswert – viel gibt es ja noch nicht – der Blog von KingCrunch, vielen wahrscheinlich bekannt aus dem deutschen [...]

  2. PHP Gangsta sagt:

    Danke für den Artikel!

    Kleine Anmerkung: Der Link zu den View Helpern (letzter Satz) ist ein lokaler Link, der so nicht funktioniert ;-)

  3. KingCrunch sagt:

    Danke für den Hinweis. Irritiert mich gerade eher, dass es so lange niemanden auffiel :D Wurde korrigiert.

Bad Behavior has blocked 73 access attempts in the last 7 days.