2013-02-23 15 views
9

Wie würde ich benutzerdefinierte Attribute in Zend Framework 2 Navigation hinzufügen?
Ich weiß, ich kann ID oder Klasse hinzufügen -> aber das ist es ....ZF2 benutzerdefinierte Attribute in der Navigation

1) Wie würde ich hinzufügen data-test='blahblah' Attribut zum Beispiel?
2) Kann ich Attribute zu li Elementen hinzufügen, die tatsächliche Links enthalten?

$container = new Zend\Navigation\Navigation(array(
    array(
     'label' => 'Page 1', 
     'id' => 'home-link', 
     'uri' => '/', 
    ), 
    array(
     'label' => 'Zend', 
     'uri' => 'http://www.zend-project.com/', 
     'order' => 100, 
    ), 
); 

Edit:

@Bram Gerritsen: Vielen Dank für Ihre Antwort.

Ja - ich kann 'data-test' => 'blahblah' hinzufügen und als $page->get('data-test') abrufen - aber das macht anhängen immer noch nicht als Attribut in <a></a> .... Würde ich ahve zu dem außer Kraft zu setzen htmlify?

Antwort

10

der Seite Klassen haben einige spezielle Setter für gemeinsame Attribute (setLabel, setId, setUri usw.) Wenn ein Setter nicht __set genannt werden existiert. Weitere Informationen hierzu sowie zur Erweiterung der Klasse AbstractPage finden Sie unter manual.

array(
    'label' => 'Page 1', 
    'id' => 'home-link', 
    'uri' => '/', 
    'data-test' => 'blahblah' 
), 

Jetzt können Sie $page->get('data_test') tun und es wird blahblah zurück.

Ihre zweite Frage bezieht sich auf die Darstellung des Menüs zu ändern (das Hinzufügen eines Attributs zu dem li. ZF2 ist die menu view helper mit einem Navigationsmenü zu machen. Alle Navigationsansicht Helfer eine Option haben eine eigene Teilansicht zu verwenden, um mit setPartial() Rendering

In Ihrem Viewscript.

$partial = array('menu.phtml', 'default'); 
$this->navigation()->menu()->setPartial($partial); 
echo $this->navigation()->menu()->render(); 

In Ihrem Teilansicht menu.phtml etwas tun, wie folgt aus:

<ul> 
<?php foreach ($this->container as $page): ?> 
    <li data-test="<?=$page->get('data_test')?>"><?=$this->navigation()->menu()->htmlify($page)?></li> 
<?php endforeach; ?> 
<ul> 

Dies wird nur die höchste Ebene des Menüs wiedergeben. Wenn Sie eine tiefere/verschachtelte Struktur haben, wird Ihr benutzerdefiniertes Ansichtsskript weitaus komplexer.

Hoffe, das hilft.

+0

Danke für Ihre Antwort. Ja - Ich kann 'data-test' => 'blahblah' hinzufügen und es als $ page-> get ('data-test') abrufen - aber dies hängt es immer noch nicht als Attribut in .. .. Würde ich htmlify dazu überschreiben müssen? –

+0

Ja, Sie müssen den Helper für Menüansichten erweitern und nur die Methode htmlify überschreiben. Schauen Sie sich die htmlify-Methode an und Sie werden ein Array von Attributen sehen. Sie können dort Ihr benutzerdefiniertes Attribut hinzufügen. Siehe meine [Antwort] (http://stackoverflow.com/questions/15017288/injecting-custom-navigation-using-a-view-helper-through-the-servicemanager/15019924#15019924) auf eine andere SO-Frage zur Registrierung Ihre eigenen Navigationshilfen anzeigen. –

+0

Danke für Ihre Antwort. Also - mein Menü hat eigentlich 2 Ebenen in der Tiefe ... Also im Wesentlichen - mit Ansicht teilweise - müsste ich rekursiv über Container iterieren - korrekt? Ich kann nicht einfach nur über Seitenelemente foreach ... –

25

Bram Antwort hat mir geholfen, hier zu einer Lösung Punkt ist das, was ich brauchte, und wie ich es gelöst (da ich zu ZF2 neu war und Namespaces es dauerte viel länger als es sollte, so hoffentlich wird dies anderen helfen)

Problem

  • Wollen Zend\Navigation verwenden, um von seiner isActive() Methode zu profitieren und die in der Übersetzung gebaut, ACL, etc Unterstützung.
  • Erforderlich zum Hinzufügen von CSS-Klassennamen zu <li> Element und<a> Element. (ZF2's Menu View Helper unterstützt derzeit einen "entweder oder" -Ansatz)
  • Erforderlich, um verschachtelten <ul> Elementen CSS-Klassennamen hinzuzufügen.
  • benötigt, um zusätzliche Attribute zum <a> Element hinzufügen wie data-*="..."
  • diese Änderungen benötigt Bootstrap 3 Auszeichnungs

Lösung Beschreibung

  • erstellen Kunden View Helfer zu unterstützen, indem sie Verlängerung Zend\View\Helper\Navigation\Menu
  • leicht ändern die renderNormalMenu() und htmlify() Methoden
  • Nutzen Sie die Möglichkeit, benutzerdefinierte Eigenschaften zu Zend\Pages hinzufügen CSS-Klassen und zusätzliche Attribute zu einigen Elementen

Lösung

hinzufügen Schritt 1

Creat ed benutzerdefinierte Ansicht Helper unter dem Anwendungsmodul src\Application\View\Helper\NewMenu.php

NewMenu.php

<?php 
namespace Application\View\Helper; 

// I'm extending this class, need to include it 
use Zend\View\Helper\Navigation\Menu; 

// Include namespaces we're using (from Zend\View\Helper\Navigation\Menu) 
use RecursiveIteratorIterator; 
use Zend\Navigation\AbstractContainer; 
use Zend\Navigation\Page\AbstractPage; 


class NewMenu extends Menu 
{ 
    // copied fromZend\View\Helper\Navigation\Menu 
    protected function renderNormalMenu(...){} 

    // copied from Zend\View\Helper\Navigation\Menu 
    public function htmlify(...){} 
} 

Schritt 2

registrierte neue Ansicht Helper mit dem getViewHelperConfig() in \module\Application\Module.php

<?php 
/** 
* Zend Framework (http://framework.zend.com/) ...*/ 

namespace Application; 

use Zend\Mvc\ModuleRouteListener; 
use Zend\Mvc\MvcEvent; 

class Module 
{ 
    // ** snip ** 

    public function getViewHelperConfig() { 
     return array(
      'invokables' => array(
       // The 'key' is what is used to call the view helper 
       'NewMenu' => 'Application\View\Helper\NewMenu', 
      ) 
     ); 
    } 
} 

Schritt 3

In meinem Skript layout.phtml erhalte ich meinen Navigationscontainer und übergebe ihn an den Helfer NewMenu View. Ich habe auch einige Optionen wie Hinzufügen der Eltern <ul> Klassenname und nicht Etiketten, so dass ich die Standard 'Dropdown-Caret', dass Bootstrap (dh. <b class="caret"></b>) zu einem Etikett mit einem Dropdown-Menü hinzufügen kann hinzugefügt.

$container = $this->navigation('navigation')->getContainer(); 
echo $this->NewMenu($container)->setUlClass('nav navbar-nav')->escapeLabels(false); 

Intermission

An dieser Stelle sollten wir mehr oder weniger haben dupliziert nur das Menü Ansicht Helper. Es sollte eine Navigation auf die gleiche Weise wie der Standard View Helper erzeugen.


Schritt 4

In der NewMenu.php Klasse, entferne ich den $addClassToListItem Code, um es zu vermeiden, die von den Klassen auf dem falschen Elemente durch Zufall platzieren.

geschützte Funktion renderNormalMenu (...)

// Add CSS class from page to <li> 
//if ($addClassToListItem && $page->getClass()) { 
// $liClasses[] = $page->getClass(); 
//} 

public function htmlify (...)

// Always apply page class to <a> tag. We'll use a diff. method for <li> 
//if ($addClassToListItem === false) { 
    $attribs['class'] = $page->getClass(); 
//} 

Schritt 5

eine Methode hinzufügen CSS Klassennamen <li> Tags anzuwenden, da wir die entfernt $addClassTolistItem Methode. Wir verwenden Sie einfach die Seite Klassen Fähigkeit, benutzerdefinierte Eigenschaften haben und dies tun:

geschützte Funktion renderNormalMenu

// Is page active? 
if ($isActive) { 
    $liClasses[] = 'active'; 
} 

if($wrapClass = $page->get('wrapClass')){ 
    $liClasses[] = $wrapClass; 
} 
... 

nun in unserer Navigation Konfigurationsdatei, können wir einfach eine Eigenschaft hinzufügen wrapClass namens CSS anwenden Klassen zum Umhüllungselement (<li>).

config \ autoload \ global.php

... 
'navigation' => array(
    'default' => array(
     ... 
     array(
      'label' => 'Products <b class="caret"></b>', 
      'route' => 'products', 
      'wrapClass' => 'dropdown',   // class to <li> 
      'class'  => 'dropdown-toggle', // class to <a> like usual 
      'pages' => array(
       array(
        'label' => 'Cars', 
        'route' => 'products/type', 
        ... 
       ), 
       ... 
      ), 
     ), 
... 

Schritt 6

Fügen Sie die Fähigkeit, sich auf <a> wie data-* zusätzliche Attribute zu haben. Für Bootstrap 3 benötigen Sie zum Beispiel data-toggle="dropdown".

public function htmlify (...)

// get attribs for element 
$attribs = array(
    'id'  => $page->getId(), 
    'title' => $title, 
); 

// add additional attributes 
$attr = $page->get('attribs'); 
if(is_array($attr)){ 
    $attribs = $attribs + $attr; 
} 

In Ihrer Konfigurationsdatei, können Sie jetzt eine Eigenschaft mit einer Reihe von zusätzlichen Attribute hinzufügen:

config \ autoload \ global. php

... 
'navigation' => array(
    'default' => array(
     ... 
     array(
      'label' => 'Products <b class="caret"></b>', 
      'route' => 'products', 
      'wrapClass' => 'dropdown',   // class to <li> 
      'class'  => 'dropdown-toggle', // class to <a> like usual 

      'attribs' => array(
       'data-toggle' => 'dropdown', // Key = Attr name, Value = Attr Value 
      ), 

      'pages' => array(
       array(
        'label' => 'Cars', 
        'route' => 'products/type', 
        ... 
       ), 
       ... 
      ), 
     ), 
... 

Schritt 7

Fügen Sie die Möglichkeit hinzu, Klassennamen in den Container für geschachtelte Listen einzufügen (d. H. <ul>).

geschützte Funktion renderNormalMenu()

if ($depth > $prevDepth) { 
    // start new ul tag 
    if ($ulClass && $depth == 0) { 
     $ulClass = ' class="' . $ulClass . '"'; 
    } 

    // Added ElseIf below 

    else if($ulClass = $page->get('pagesContainerClass')){ 
     $ulClass = ' class="' . $ulClass . '"'; 
    } 

    else { 
     $ulClass = ''; 
    } 
    $html .= $myIndent . '<ul' . $ulClass . '>' . self::EOL; 

Der ursprüngliche Code im Grunde gesagt, „wenn dies die ersten <ul> und es gibt eine UL-Klasse ist, fügen Sie es, sonst nichts tun. Also, hat er eine zusätzliche Kontrolle . zu sagen, wenn eine Eigenschaft namens pagesContainerClass zur Verfügung steht, als auch die Klasse die <ul> anzuwenden

Dies bedeutet, dass wir die Eigenschaft auf der rechten Seite in unserer Konfiguration hinzufügen müssen:

config \ autoload \ global.php

... 
'navigation' => array(
    'default' => array(
     ... 
     array(
      'label' => 'Products <b class="caret"></b>', 
      'route' => 'products', 
      'wrapClass' => 'dropdown',   // class to <li> 
      'class'  => 'dropdown-toggle', // class to <a> like usual 

      'attribs' => array(
       'data-toggle' => 'dropdown', // Key = Attr name, Value = Attr Value 
      ), 

      'pages' => array(
       array(
        'label' => 'Cars', 
        'route' => 'products/type', 
        // Give child <ul> a class name 
        'pagesContainerClass' => 'dropdown-menu', 
        ... 
       ), 
       ... 
      ), 
     ), 
... 

Wichtig zu beachten, muss die UL-Klasse auf dem ersten Kind Seite eines Kindes gelegt werden, da die bedingte Anweisungen in einem der folgenden Bedingung eingewickelt werden:

if ($depth > $prevDepth) { 
    // start new ul tag 
    ... 
} 

Nach dem ersten child wird aufgerufen, $ dept = $ prevDepth und die verschachtelten <ul> wurden bereits an den Zeichenfolgenpuffer gesendet.


Diese Lösung wurde nicht rigoros getestet, aber die Idee ist, dass einfach nimmt, ist das aktuelle Menü Ansicht Helper, und Überlastungen, die beiden notwendigen Methoden und nur geringfügig geändert, dass.

Ich habe versucht, setPartial() zu verwenden, aber das nur mit der <li> Generation geholfen, es immer noch der Menüansicht Helpers' htmlify() Verfahren wurde mit (von denen alle in Bram Diskussion oben erwähnt wurde).

So jene kleine tweeks auf die Verfahren mit der Herstellung und Verwendung der Fähigkeit der Page-Klasse benutzerdefinierten Eigenschaften zu haben, konnte ich nur einige zusätzliche Logik in den Klassennamen auf den <li>, <a> und verschachtelt <ul> Klassen sowie fügen Sie zusätzliche bekommen Eigenschaften auf den <a> Elementen, so dass ich meine Zend\Navigation von der Konfiguration konfigurieren konnte, um im Grunde Bootstrap 3 Navbar Markup ausspucken.

Das Ende-Layout dann sieht genauso aus wie folgt aus:

<nav class="navbar navbar-default navbar-static-top" role="navigation"> 
    <div class="navbar-header"> 
     <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-ex1-collapse"> 
      <span class="sr-only">Toggle navigation</span> 
      <span class="icon-bar"></span> 
      <span class="icon-bar"></span> 
      <span class="icon-bar"></span> 
     </button> 
    </div> 
    <div class="collapse navbar-collapse navbar-ex1-collapse"> 
    <?php 
     // Use Zend\Navigation to create the menu 
     $container = $this->navigation('navigation')->getContainer(); 
     echo $this->NewMenu($container)->setUlClass('nav navbar-nav')->escapeLabels(false); 
    ?> 
    </div><!-- /.navbar-collapse --> 
</nav> 

Die Unruhen ich in Betrieb gehalten ein besseres Verständnis von PHP Namespaces war und die entsprechenden Qualified Namespaces in meiner benutzerdefinierten Ansicht Helper, obwohl aufzunehmen benötigt zu haben Ich habe es verlängert.

Das andere Problem war, dass die Navigationsansicht Helper das Menü Ansicht Helper von selbst wie so nennen kann:

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

arbeiten Dies wird nicht:

$this->navigation('navigation')->NewMenu(); 

, weil ich denke, von Namespace-Problemen mit NewMenu nicht in der Navigation View Helper-Klasse registriert und ich werde es nicht nur dafür erweitern.

Also, hoffentlich wird diese (lange) Antwort anderen helfen, die mit dieser Notwendigkeit kämpfen.

Prost!

+0

TOP !! einfach toll, könnte nicht klarer sein und wirkt wie ein Charme ... – cwhisperer

1

Neben jmbertucci Kommentar

Problem

exсess caret Tag in Etikett, das Problem verursachen mit:

  • Paniermehl
  • Menü Übersetzung

Splution

Um das Hinzufügen des Tags Caret zu verhindern, können Sie die Unterstützung dieses Parameters im Menü config hinzufügen. Sie sollten

Zum

src\Application\View\Helper\NewMenu.php 

geschützten Funktion renderNormalMenu()

/// add 4th parameter $page->get('caret') 
$html .= $myIndent . ' <li' . $liClass . '>' . PHP_EOL . 
$myIndent . '  ' . 
$this->htmlify($page, $escapeLabels, $addClassToListItem, $page->get('caret')) . PHP_EOL; 

public function htmlify()

} else { 
    $html .= $label; 
} 
//// add this if 
if($caret === true){ 
    $html .= '<b class="caret"></b>'; 
} 

$html .= '</' . $element . '>'; 

Jetzt können Sie es verwenden:

array(
       'label' => 'Some label', 
       'caret' => true, 
       'route' => 'someroute', 
       'wrapClass' => 'dropdown', 
       'class' => 'dropdown-toggle', 

ps. jmbertucci, du bist der Mann.

Verwandte Themen