导航中的ZF2自定义属性

age*_*ith 9 zend-framework2

如何在Zend Framework 2导航中添加自定义属性?
我知道我可以添加id或类 - >但这就是它....

1)我如何添加data-test='blahblah'属性例如?
2)我可以为li包含实际链接的元素添加属性吗?

$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,
    ),
);
Run Code Online (Sandbox Code Playgroud)

编辑:

@Bram Gerritsen:谢谢你的回答.

是的 - 我可以添加'data-test' => 'blahblah'和检索它$page->get('data-test') - 但是这仍然不会将其作为属性附加到<a></a>....我是否应该将htmlify覆盖到那个?

jmb*_*cci 25

Bram的回答帮助我找到了解决方案,这就是我需要的以及我如何解决它(因为我是ZF2和命名空间的新手,它花了我的时间比它应该有的长,所以希望这会有助于其他人)

问题

  • 想要使用Zend\Navigation它的isActive()方法和内置的翻译,ACL等支持.
  • 需要将CSS类名添加到<li>元素 <a>元素中.(ZF2的菜单视图助手目前支持'或'或'方法)
  • 需要将CSS类名添加到嵌套<ul>元素.
  • 需要向<a>元素添加其他属性,例如data-*="..."
  • 需要这些更改才能支持Bootstrap 3标记

解决方案描述

  • 通过扩展创建客户视图助手 Zend\View\Helper\Navigation\Menu
  • 稍微修改renderNormalMenu()htmlify()方法
  • 利用添加自定义属性的功能,Zend\Pages可以将CSS类和其他属性添加到某些元素中

步骤1

在Application模块下创建自定义View Helper 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(...){}
}
Run Code Online (Sandbox Code Playgroud)

第2步

注册新的View Helper with 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',
            )
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

第3步

在我的layout.phtml脚本中,我获取了我的导航容器并将其传递给NewMenu视图助手.我还设置了一些选项,比如添加父<ul>类名称而不是转义标签,这样我就可以将Bootstrap使用的标准"下拉插入符号"(即.<b class="caret"></b>)添加到带有下拉菜单的标签中.

$container = $this->navigation('navigation')->getContainer();
echo $this->NewMenu($container)->setUlClass('nav navbar-nav')->escapeLabels(false);
Run Code Online (Sandbox Code Playgroud)

幕间休息

此时,我们应该或多或少地重复菜单视图助手.它应该以与标准View Helper相同的方式生成导航.


第4步

NewMenu.php类中,我删除$addClassToListItem代码以避免它意外地将类放在错误的元素上.

受保护的函数renderNormalMenu(...)

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

公共功能htmlify(...)

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

第5步

添加一个方法将CSS类名应用于<li>标记,因为我们删除了该$addClassTolistItem方法.我们只是使用Page classes功能来拥有自定义属性并执行以下操作:

受保护的函数renderNormalMenu

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

if($wrapClass = $page->get('wrapClass')){
    $liClasses[] = $wrapClass;
}
...
Run Code Online (Sandbox Code Playgroud)

现在,在我们的Navigation配置文件中,我们可以简单地添加一个名为wrapClass将CSS类应用于包装元素(<li>)的属性.

配置\自动加载\ 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',
                    ...
                ),
                ...
            ),
        ),
...
Run Code Online (Sandbox Code Playgroud)

第6步

加入有附加属性的能力<a>一样data-*.例如,对于Bootstrap 3,您需要data-toggle="dropdown".

公共功能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;
}
Run Code Online (Sandbox Code Playgroud)

在配置文件中,您现在可以添加具有其他属性数组的属性:

配置\自动加载\ 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',
                    ...
                ),
                ...
            ),
        ),
...
Run Code Online (Sandbox Code Playgroud)

第7步

添加在嵌套列表容器上放置类名的功能(即.<ul>).

受保护的函数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;
Run Code Online (Sandbox Code Playgroud)

原始代码基本上说"如果这是第一个<ul>并且有一个UL类,添加它,否则什么都不做.所以,我添加了一个额外的检查,如果一个被调用的属性pagesContainerClass可用,也可以将类应用到那个<ul>.

这意味着我们需要在配置中的右侧页面上添加属性:

配置\自动加载\ 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',
                    ...
                ),
                ...
            ),
        ),
...
Run Code Online (Sandbox Code Playgroud)

需要注意的是,UL类需要放在子节点的第一个子页面上,因为条件语句包含在以下条件中:

if ($depth > $prevDepth) {
    // start new ul tag
    ...
}
Run Code Online (Sandbox Code Playgroud)

调用第一个子节点后,$ dept = $ prevDepth和嵌套<ul>将已经发送到字符串缓冲区.


这个解决方案还没有经过严格的测试,但想法是简单地使用当前的菜单视图助手,并重载两个必要的方法,只是略微修改它.

我试图使用,setPartial()但这只对这<li>一代有所帮助,它仍然使用菜单视图助手的htmlify()方法(所有这些都在Bram上面的讨论中提到过).

因此,与使这些小tweeks的方法和使用Page类的能力,具有自定义属性,我可以添加一些额外的逻辑来获得类名<li>,<a>并嵌套<ul>类以及在添加附加属性<a>的元素,所以我可以配置我Zend\Navigation从配置吐出,基本上,Bootstrap 3 Navbar标记.

结束布局然后看起来像这样:

<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>
Run Code Online (Sandbox Code Playgroud)

我遇到的麻烦是更好地理解PHP命名空间,并且需要在我的自定义View Helper中包含适当的Qualified名称空间,即使我正在扩展它.

另一个问题是导航视图助手可以像这样调用菜单视图助手:

$this->navigation('navigation')->menu();
Run Code Online (Sandbox Code Playgroud)

这不起作用:

$this->navigation('navigation')->NewMenu();
Run Code Online (Sandbox Code Playgroud)

我正在考虑因为NewMenu没有在Navigation View Helper类中注册的命名空间问题,我不打算仅为此扩展它.

因此,希望这个(长期)答案将帮助那些正在努力满足这一需求的人.

干杯!


Bra*_*sen 10

该页面类具有共同属性(一些专门制定者setLabel,setId,setUri等),如果不制定者存在__set将被调用.有关此内容以及有关扩展课程的详细信息,请参阅手册AbstractPage.

array(
    'label' => 'Page 1',
    'id' => 'home-link',
    'uri' => '/',
    'data-test' => 'blahblah'
),
Run Code Online (Sandbox Code Playgroud)

现在你可以做$page->get('data_test'),它将返回blahblah.

第二个问题是改变菜单的渲染(向liZF2 添加一个属性.ZF2正在使用菜单视图助手来渲染导航菜单.所有导航视图助手都可以选择使用您自己的局部视图进行渲染setPartial().

在你的意见中:

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

在您的局部视图中menu.phtml执行以下操作:

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

这只会呈现菜单的最高级别.如果您有更深层/嵌套的结构,您的自定义视图脚本将会变得更加复杂.

希望这可以帮助.