导航中的ZF2自定义属性

时间:2013-02-23 04:52:33

标签: zend-framework2

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

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,
    ),
);

编辑:

@Bram Gerritsen:谢谢你的回答。

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

3 个答案:

答案 0 :(得分:25)

Bram的回答帮助我找到了一个解决方案,这就是我需要的东西以及我是如何解决它的(因为我是ZF2和名称空间的新手,它花了我更长的时间,所以希望如此这将有助于其他人)

<强>问题

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

解决方案说明

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

<强>解决方案

第1步

在应用程序模块src\Application\View\Helper\NewMenu.php

下创建自定义View Helper

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(...){}
}

第2步

getViewHelperConfig()

中使用\module\Application\Module.php注册了新的View帮助程序
<?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',
            )
        );
    }
}

第3步

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

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

<强>间歇

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


第4步

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

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

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

公共功能htmlify(...)

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

第5步

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

受保护的函数renderNormalMenu

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

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

现在,在我们的导航配置文件中,我们可以简单地添加一个名为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',
                    ...
                ),
                ...
            ),
        ),
...

第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;
}

在配置文件中,您现在可以添加一个包含其他属性数组的属性:

设置\自动加载\ 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',
                    ...
                ),
                ...
            ),
        ),
...

第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;

原始代码基本上说&#34;如果这是第一个<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',
                    ...
                ),
                ...
            ),
        ),
...

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

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

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


此解决方案尚未经过严格测试,但其理念是简单地使用当前的菜单视图助手,并重载两个必要的方法,并稍微修改一下。

我已经尝试使用setPartial(),但这仅对<li>代产生了帮助,它仍然使用菜单视图助手&#39; htmlify()方法(所有这些都在Bram上面的讨论中提到过。)

因此,通过将这些小小的tweek用于to方法并使用Page类具有自定义属性的能力,我可以添加一些额外的逻辑来获取<li>上的类名,{{1 }和嵌套的<a>类以及在<ul>元素上添加其他属性,因此我可以从配置中配置我的<a>以吐出,基本上是Bootstrap 3 Navbar标记。 / p>

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

Zend\Navigation

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

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

<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>

这不会起作用:

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

我正在考虑因$this->navigation('navigation')->NewMenu(); 没有在导航视图助手类中注册的名称空间问题,而且我不会仅为此扩展它。

所以,希望这个(长期)答案可以帮助那些正在努力满足这种需求的人。

干杯!

答案 1 :(得分:10)

Page类有一些专用的公共属性设置器(setLabelsetIdsetUri等),如果不存在setter __set将被调用。有关此问题以及有关扩展AbstractPage类的详细信息,请参阅manual

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

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

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

在你的意见稿中:

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

在您的部分视图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>

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

希望这有帮助。

答案 2 :(得分:1)

除了 jmbertucci 评论

问题

ex.gess标签中的插入标签导致问题:

  • 面包屑
  • 菜单翻译

Splution

要防止将标签插入符号添加到标签,您可以在菜单配置中添加对此参数的支持。你应该

转到

src\Application\View\Helper\NewMenu.php

受保护的函数renderNormalMenu()

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

公共职能htmlify()

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

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

现在你可以使用它了:

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

ps。 jmbertucci ,你是男人。