mimmi20/mezzio-navigation-laminasviewrenderer

为Mezzio导航提供视图助手

3.0.4 2024-09-13 04:54 UTC

README

Latest Stable Version Latest Unstable Version License

代码状态

codecov Test Coverage Average time to resolve an issue Percentage of issues still open Mutation testing badge Maintainability

安装

运行

composer require mimmi20/mezzio-navigation-laminasviewrenderer

渲染导航

在布局脚本中调用菜单视图助手

<!-- ... -->

<body>
    <?= $this->navigation('default')->menu() ?>
</body>
<!-- ... -->

使用多个导航

一旦注册了mezzio-navigation模块,您就可以创建任意数量的导航定义,底层的工厂将自动创建导航容器。

将容器定义添加到配置文件中,例如 config/autoload/global.php

<?php
return [
    // ...

    'navigation' => [

        // Navigation with name default
        'default' => [
            [
                'label' => 'Home',
                'route' => 'home',
            ],
            [
                'label' => 'Page #1',
                'route' => 'page-1',
                'pages' => [
                    [
                        'label' => 'Child #1',
                        'route' => 'page-1-child',
                    ],
                ],
            ],
            [
                'label' => 'Page #2',
                'route' => 'page-2',
            ],
        ],

        // Navigation with name special
        'special' => [
            [
                'label' => 'Special',
                'route' => 'special',
            ],
            [
                'label' => 'Special Page #2',
                'route' => 'special-2',
            ],
        ],

        // Navigation with name sitemap
        'sitemap' => [
            [
                'label' => 'Sitemap',
                'route' => 'sitemap',
            ],
            [
                'label' => 'Sitemap Page #2',
                'route' => 'sitemap-2',
            ],
        ],
    ],
    // ...
];

容器名称有前缀

当使用mezzio-navigation作为模块时,有一个重要点需要注意:在您的视图脚本中,容器的名称必须Mezzio\Navigation\为前缀,后跟配置键的名称。这有助于确保不会与其他服务发生名称冲突。

以下示例演示了渲染名为defaultspecialsitemap的容器导航菜单。

<!-- ... -->

<body>
    <?= $this->navigation('Mimmi20\Mezzio\Navigation\Default')->menu() ?>

    <?= $this->navigation('Mimmi20\Navigation\Special')->menu() ?>

    <?= $this->navigation('Mimmi20\Navigation\Sitemap')->menu() ?>
</body>
<!-- ... -->

视图助手

导航助手用于从Mimmi20\Mezzio\Navigation\Navigation实例渲染导航元素。

有5个内置助手

  • 面包屑,用于渲染当前活动页面的路径。
  • 链接,用于渲染导航头部链接(例如 <link rel="next" href="..." />)。
  • 菜单,用于渲染菜单。
  • 站点地图,用于渲染符合Sitemaps XML格式的站点地图。
  • 导航,用于代理对其他导航助手的调用。

所有内置助手都实现了接口Mezzio\Navigation\LaminasView\View\Helper\Navigation\ViewHelperInterface,它增加了与laminas-acllaminas-rbac以及laminas-i18n的集成。该接口Mimmi20\Mezzio\Navigation\Helper\Navigation\HelperInterface定义了以下方法

除了接口中的方法存根之外,抽象类还实现了以下方法

如果没有显式设置容器,助手将在调用$helper->getContainer()时创建一个空的Mimmi20\Mezzio\Navigation\Navigation容器。

代理对导航容器的调用

导航视图助手使用魔法方法__call()将方法调用代理到在视图助手中注册的导航容器。

$this->navigation()->addPage([
    'type' => 'uri',
    'label' => 'New page',
]);

上面的调用将在Navigation助手中的容器中添加一个页面。

标签和标题的翻译

导航助手支持页面标签和标题的翻译。您可以在助手中使用$helper->setTranslator($translator)设置类型为Laminas\I18n\Translator\TranslatorInterface的翻译器。

如果您想禁用翻译,请使用$helper->setTranslatorEnabled(false)

代理助手将向它代理的助手中注入它自己的翻译器,如果代理助手尚未具有翻译器。

站点地图不使用翻译

由于XML站点地图中不涉及页面标签或标题,因此站点地图助手中没有翻译。

与ACL集成

所有导航视图助手都支持访问控制列表(ACL)。任何实现 Laminas\Permissions\Acl\AclInterface 接口的对象都可以通过 $helper->setAcl($acl) 分配给助手实例,并通过 $helper->setRole('member')$helper->setRole(new Laminas\Permissions\Acl\Role\GenericRole('member')) 设置角色。如果助手中使用了ACL,则助手中的角色必须被ACL允许访问页面上的 resource 和/或具有页面的 privilege,以便在渲染时包含该页面。

如果页面不被ACL接受,任何子页面也将被排除在渲染之外。

下面的 代理助手 将将其自己的ACL和角色注入它代理的助手,如果代理助手尚未设置任何内容。

下面的示例都显示了ACL如何影响渲染。

示例中使用的导航设置

本例展示了为一家虚构的软件公司设置导航容器的示例。

关于设置的说明

  • 网站的域是 www.example.com
  • 有趣的页面属性以注释标记。
  • 除非在其他示例中另有说明,用户请求的是URL http://www.example.com/products/server/faq/,这对应于“Foo Server”下的 FAQ 标签页。
  • 以下是在容器设置下方显示的假设的ACL和路由设置。
use Mimmi20\Mezzio\Navigation\Navigation;

/*
 * Navigation container

 * Each element in the array will be passed to
 * Mimmi20\Mezzio\Navigation\Page\(new PageFactory())->factory() when constructing
 * the navigation container below.
 */
$pages = [
    [
        'label'      => 'Home',
        'title'      => 'Go Home',
        'module'     => 'default',
        'controller' => 'index',
        'action'     => 'index',
        'order'      => -100, // make sure home is the first page
    ],
    [
        'label'      => 'Special offer this week only!',
        'module'     => 'store',
        'controller' => 'offer',
        'action'     => 'amazing',
        'visible'    => false, // not visible
    ],
    [
        'label'      => 'Products',
        'module'     => 'products',
        'controller' => 'index',
        'action'     => 'index',
        'pages'      => [
            [
                'label'      => 'Foo Server',
                'module'     => 'products',
                'controller' => 'server',
                'action'     => 'index',
                'pages'      => [
                    [
                        'label'      => 'FAQ',
                        'module'     => 'products',
                        'controller' => 'server',
                        'action'     => 'faq',
                        'rel'        => [
                            'canonical' => 'http://www.example.com/?page=faq',
                            'alternate' => [
                                'module'     => 'products',
                                'controller' => 'server',
                                'action'     => 'faq',
                                'params'     => ['format' => 'xml'],
                            ],
                        ],
                    ],
                    [
                        'label'      => 'Editions',
                        'module'     => 'products',
                        'controller' => 'server',
                        'action'     => 'editions',
                    ],
                    [
                        'label'      => 'System Requirements',
                        'module'     => 'products',
                        'controller' => 'server',
                        'action'     => 'requirements',
                    ],
                ],
            ],
            [
                'label'      => 'Foo Studio',
                'module'     => 'products',
                'controller' => 'studio',
                'action'     => 'index',
                'pages'      => [
                    [
                        'label'      => 'Customer Stories',
                        'module'     => 'products',
                        'controller' => 'studio',
                        'action'     => 'customers',
                    ],
                    [
                        'label'      => 'Support',
                        'module'     => 'products',
                        'controller' => 'studio',
                        'action'     => 'support',
                    ],
                ],
            ],
        ],
    ],
    [
        'label'      => 'Company',
        'title'      => 'About us',
        'module'     => 'company',
        'controller' => 'about',
        'action'     => 'index',
        'pages'      => [
            [
                'label'      => 'Investor Relations',
                'module'     => 'company',
                'controller' => 'about',
                'action'     => 'investors',
            ],
            [
                'label'      => 'News',
                'class'      => 'rss', // class
                'module'     => 'company',
                'controller' => 'news',
                'action'     => 'index',
                'pages'      => [
                    [
                        'label'      => 'Press Releases',
                        'module'     => 'company',
                        'controller' => 'news',
                        'action'     => 'press',
                    ],
                    [
                        'label'      => 'Archive',
                        'route'      => 'archive', // route
                        'module'     => 'company',
                        'controller' => 'news',
                        'action'     => 'archive',
                    ],
                ],
            ],
        ],
    ],
    [
        'label'      => 'Community',
        'module'     => 'community',
        'controller' => 'index',
        'action'     => 'index',
        'pages'      => [
            [
                'label'      => 'My Account',
                'module'     => 'community',
                'controller' => 'account',
                'action'     => 'index',
                'resource'   => 'mvc:community.account', // resource
            ],
            [
                'label' => 'Forums',
                'uri'   => 'http://forums.example.com/',
                'class' => 'external', // class,
            ],
        ],
    ],
    [
        'label'      => 'Administration',
        'module'     => 'admin',
        'controller' => 'index',
        'action'     => 'index',
        'resource'   => 'mvc:admin', // resource
        'pages'      => [
            [
                'label'      => 'Write new article',
                'module'     => 'admin',
                'controller' => 'post',
                'action'     => 'write',
            ],
        ],
    ],
];

// Create container from array
$container = new Navigation();
$container->addPages($pages);

// Store the container in the proxy helper:
$view->plugin('navigation')->setContainer($container);

// ...or simply:
$view->navigation($container);

除了上面的容器外,还向模块的配置文件中添加了以下路由设置,例如 module/MyModule/config/module.config.php

return [
    /* ... */
    'router' [
        'routes' => [
            'archive' => [
                'type'    => 'Segment',
                'options' => [
                    'route'    => '/archive/:year',
                    'defaults' => [
                        'module'     => 'company',
                        'controller' => 'news',
                        'action'     => 'archive',
                        'year'       => (int) date('Y') - 1,
                    ],
                    'constraints' => [
                        'year' => '\d+',
                    ],
                ],
            ],
            /* You can have other routes here... */
        ],
    ],
    /* ... */
];

ACL的设置可以在模块类中完成,例如 module/MyModule/Module.php

namespace MyModule;

use Laminas\View\HelperPluginManager as ViewHelperPluginManager;
use Laminas\Permissions\Acl\Acl;
use Laminas\Permissions\Acl\Role\GenericRole;
use Laminas\Permissions\Acl\Resource\GenericResource;

class Module
{
    /* ... */
    public function getViewHelperConfig()
    {
        return [
            'factories' => [
                // This will overwrite the native navigation helper
                'navigation' => function(ViewHelperPluginManager $pm) {
                    // Setup ACL:
                    $acl = new Acl();
                    $acl->addRole(new GenericRole('member'));
                    $acl->addRole(new GenericRole('admin'));
                    $acl->addResource(new GenericResource('mvc:admin'));
                    $acl->addResource(new GenericResource('mvc:community.account'));
                    $acl->allow('member', 'mvc:community.account');
                    $acl->allow('admin', null);

                    // Get an instance of the proxy helper
                    $navigation = $pm->get('Mezzio\Navigation\Helper\Navigation');

                    // Store ACL and role in the proxy helper:
                    $navigation->setAcl($acl);
                    $navigation->setRole('member');

                    // Return the new navigation helper instance
                    return $navigation;
                }
            ]
        ];
    }
    /* ... */
}

导航代理

navigation() 助手是一个代理助手,它将调用传递给其他导航助手。它可以被认为是所有导航相关视图任务的入口点。

Navigation 助手查找实现 Mezzio\Navigation\Helper\Navigation\HelperInterface 的其他助手,这意味着自定义视图助手也可以被代理。然而,这需要将自定义助手路径添加到视图中。

在代理到其他助手时,Navigation 助手可以注入其容器、ACL和可选的角色以及翻译器。这意味着您不必在所有导航助手中明确设置这三个元素,也不必通过静态方法注入。

方法

面包屑

面包屑用于指示用户当前在网站结构中的位置,通常像以下这样渲染:

You are here: Home > Products > FantasticProduct 1.0

breadcrumbs() 助手遵循Yahoo!设计模式库中概述的 面包屑模式,并允许简单的自定义(最小/最大深度、缩进、分隔符以及是否将最后一个元素链接),或使用部分视图脚本进行渲染。

面包屑助手找到导航容器中最深的活跃页面,并渲染到根的向上路径。对于页面,页面的“活跃性”通过检查请求对象来确定,如页面部分所述。

助手默认将 minDepth 属性设置为1,这意味着如果最深的活跃页面是根页面,则不会渲染面包屑。如果指定了 maxDepth,则助手将在达到指定深度时停止渲染(例如,即使在最深的活跃页面在第3级,也将在第2级停止)。

面包屑助手中的方法

基本用法

此示例显示了如何使用默认设置渲染面包屑。

在视图脚本或布局中

<?= $this->navigation()->breadcrumbs(); ?>

上面的调用利用了神奇的 __toString() 方法,等同于:

<?= $this->navigation()->breadcrumbs()->render(); ?>

输出

<a href="/products">Products</a> &gt; <a href="/products/server">Foo Server</a> &gt; FAQ

指定缩进

此示例显示了如何带有初始缩进渲染面包屑。

使用8个空格缩进渲染

<?= $this->navigation()->breadcrumbs()->setIndent(8) ?>

输出

        <a href="/products">Products</a> &gt; <a href="/products/server">Foo Server</a> &gt; FAQ

自定义输出

此示例显示了如何通过指定多个选项来自定义面包屑输出。

在视图脚本或布局中

<?= $this->navigation()->breadcrumbs()
    ->setLinkLast(true)                   // link last page
    ->setMaxDepth(1)                      // stop at level 1
    ->setSeparator('' . PHP_EOL);       // cool separator with newline
?>

输出

<a href="/products">Products</a><a href="/products/server">Foo Server</a>

设置渲染面包屑所需的最小深度

<?= $this->navigation()->breadcrumbs()->setMinDepth(10) ?>

输出:无,因为最深的活跃页面不在第10级或更深处。

使用部分视图脚本进行渲染

此示例展示了如何使用部分视图脚本渲染自定义的面包屑。通过调用setPartial(),您可以为调用render()时使用指定部分视图脚本来指定部分视图脚本。当指定了部分视图时,在生成面包屑时会调用renderPartial()方法。此方法将找到最深的活跃页面,并将指向活跃页面的页面数组传递给部分视图脚本。

在布局中

echo $this->navigation()->breadcrumbs()
    ->setPartial('my-module/partials/breadcrumbs');

module/MyModule/view/my-module/partials/breadcrumbs.phtml的内容

<?= implode(', ', array_map(function ($a) {
  return $a->getLabel();
}, $this->pages)); ?>

输出

Products, Foo Server, FAQ

链接

使用links()辅助函数来渲染HTML LINK元素。链接用于描述当前活跃页面的文档关系。更多关于链接和链接类型的信息,请参阅

存在两种关系类型;正向和反向,分别由关键词relrev表示。辅助函数中的大多数方法将接受一个$rel参数,该参数必须是relrev。大多数方法还接受一个$type参数,该参数用于指定链接类型(例如,alternatestartnextprevchapter等)。

关系可以手动添加到页面对象中,或通过遍历辅助函数中注册的容器来找到。方法findRelation($page, $rel, $type)将首先尝试通过调用$page>findRel($type)$page>findRel($type)$page中找到给定的$rel类型的$type。如果$page有一个可以转换为页面实例的关系,则将使用该关系。如果$page实例没有指定的$type,辅助函数将查找辅助函数中名为search$rel$type(例如,searchRelNext()searchRevAlternate())的方法。如果存在这样的方法,它将用于通过遍历容器来确定$page的关系。

并非所有关系都可以通过遍历容器来确定。以下是通过搜索找到的关系

  • searchRelStart(),正向start关系:容器中的第一个页面。
  • searchRelNext(),正向next关系;找到容器中的下一个页面,即活跃页面之后的页面。
  • searchRelPrev(),正向prev关系;找到上一个页面,即活跃页面之前的页面。
  • searchRelChapter(),正向chapter关系;找到级别0上的所有页面,除了start关系或如果它在级别0上,则是活跃页面。
  • searchRelSection(),正向section关系;如果活跃页面在级别0(一个chapter),则找到活跃页面的所有子页面。
  • searchRelSubsection(),正向subsection关系;如果活跃页面在级别1(一个section),则找到活跃页面的所有子页面。
  • searchRevSection(),反向section关系;如果活跃页面在级别1(一个section),则找到活跃页面的父页面。
  • searchRevSubsection(),反向subsection关系;如果活跃页面在级别2(一个subsection),则找到活跃页面的父页面。

允许的关系类型

在查找页面实例中的关系时($page->getRel($type)$page>getRev($type)),辅助函数接受类型为stringarrayTraversableMezzio\Navigation\Page\PageInterface的值。

  • 直接使用PageInterface实例。
  • 如果找到一个字符串,它将被转换为Mezzio\Navigation\Page\Uri
  • 如果找到数组或可遍历对象,它将被转换为一个或多个页面实例。如果第一个键是数字,则认为它包含多个页面,每个元素都将传递给页面工厂。如果第一个键不是数字,则直接将值传递给页面工厂,并返回一个单独的页面。

辅助工具还支持用于查找关系的魔法方法。例如,要查找正向备用关系,请调用$helper->findRelAlternate($page),要查找反向章节关系,请调用$helper->findRevSection($page)。这些调用分别对应于$helper->findRelation($page, 'rel', 'alternate')$helper->findRelation($page, 'rev', 'section')

要自定义应渲染哪些关系,辅助工具使用渲染标志。渲染标志是一个整数值,它将与辅助工具的渲染常量进行位与(&)运算,以确定是否渲染属于渲染常量的关系。

请参阅以下示例以获取更多信息。

LinksInterface辅助工具定义了以下常量

  • Mezzio\Navigation\Helper\Navigation\LinksInterface::RENDER_ALTERNATE
  • Mezzio\Navigation\Helper\Navigation\LinksInterface::RENDER_STYLESHEET
  • Mezzio\Navigation\Helper\Navigation\LinksInterface::RENDER_START
  • Mezzio\Navigation\Helper\Navigation\LinksInterface::RENDER_NEXT
  • Mezzio\Navigation\Helper\Navigation\LinksInterface::RENDER_PREV
  • Mezzio\Navigation\Helper\Navigation\LinksInterface::RENDER_CONTENTS
  • Mezzio\Navigation\Helper\Navigation\LinksInterface::RENDER_INDEX
  • Mezzio\Navigation\Helper\Navigation\LinksInterface::RENDER_GLOSSARY
  • Mezzio\Navigation\Helper\Navigation\LinksInterface::RENDER_COPYRIGHT
  • Mezzio\Navigation\Helper\Navigation\LinksInterface::RENDER_CHAPTER
  • Mezzio\Navigation\Helper\Navigation\LinksInterface::RENDER_SECTION
  • Mezzio\Navigation\Helper\Navigation\LinksInterface::RENDER_SUBSECTION
  • Mezzio\Navigation\Helper\Navigation\LinksInterface::RENDER_APPENDIX
  • Mezzio\Navigation\Helper\Navigation\LinksInterface::RENDER_HELP
  • Mezzio\Navigation\Helper\Navigation\LinksInterface::RENDER_BOOKMARK
  • Mezzio\Navigation\Helper\Navigation\LinksInterface::RENDER_CUSTOM
  • Mezzio\Navigation\Helper\Navigation\LinksInterface::RENDER_ALL

RENDER_ALTERNATERENDER_BOOKMARK的常量表示标准的HTML链接类型。RENDER_CUSTOM表示在页面中指定的非标准关系。RENDER_ALL表示标准和非标准关系。

链接辅助工具中的方法

基本用法

在页面中指定关系

此示例显示了如何在页面中指定关系。

use Laminas\Config\Config;
use Mimmi20\Mezzio\Navigation\Navigation;
use Mimmi20\Mezzio\Navigation\Page\PageInterface;

$container = new Navigation([
    [
        'label' => 'Relations using strings',
        'rel'   => [
            'alternate' => 'http://www.example.org/',
        ],
        'rev'   => [
            'alternate' => 'http://www.example.net/',
        ],
    ],
    [
        'label' => 'Relations using arrays',
        'rel'   => [
            'alternate' => [
                'label' => 'Example.org',
                'uri'   => 'http://www.example.org/',
            ],
        ],
    ],
    [
        'label' => 'Relations using configs',
        'rel'   => [
            'alternate' => new Config([
                'label' => 'Example.org',
                'uri'   => 'http://www.example.org/',
            ]),
        ],
    ],
    [
        'label' => 'Relations using pages instance',
        'rel'   => [
            'alternate' => (new PageFactory())->factory([
                'label' => 'Example.org',
                'uri'   => 'http://www.example.org/',
            ]),
        ],
    ],
]);

链接的默认渲染

此示例显示了如何从在视图辅助工具中注册的容器中渲染菜单。

在视图脚本或布局中

<?= $this->navigation()->links() ?>

输出

<link rel="alternate" href="/products/server/faq/format/xml">
<link rel="start" href="/" title="Home">
<link rel="next" href="/products/server/editions" title="Editions">
<link rel="prev" href="/products/server" title="Foo Server">
<link rel="chapter" href="/products" title="Products">
<link rel="chapter" href="/company/about" title="Company">
<link rel="chapter" href="/community" title="Community">
<link rel="canonical" href="http://www.example.com/?page=server-faq">
<link rev="subsection" href="/products/server" title="Foo Server">

指定要渲染哪些关系

此示例显示了如何指定要查找和渲染的关系。

仅渲染开始、下一页和上一页

use Mimmi20\Mezzio\Navigation\Helper\Navigation\LinksInterface;

$links = $this->navigation()->links();
$links->setRenderFlag(LinksInterface::RENDER_START | LinksInterface::RENDER_NEXT | LinksInterface::RENDER_PREV);
echo $links;

输出

<link rel="start" href="/" title="Home">
<link rel="next" href="/products/server/editions" title="Editions">
<link rel="prev" href="/products/server" title="Foo Server">

仅渲染原生链接类型

$links->setRenderFlag(LinksInterface::RENDER_ALL ^ LinksInterface::RENDER_CUSTOM);
echo $links;

输出

<link rel="alternate" href="/products/server/faq/format/xml">
<link rel="start" href="/" title="Home">
<link rel="next" href="/products/server/editions" title="Editions">
<link rel="prev" href="/products/server" title="Foo Server">
<link rel="chapter" href="/products" title="Products">
<link rel="chapter" href="/company/about" title="Company">
<link rel="chapter" href="/community" title="Community">
<link rev="subsection" href="/products/server" title="Foo Server">

除了章节之外,渲染所有内容

$links->setRenderFlag(Links::RENDER_ALL ^ Links::RENDER_CHAPTER);
echo $links;

输出

<link rel="alternate" href="/products/server/faq/format/xml">
<link rel="start" href="/" title="Home">
<link rel="next" href="/products/server/editions" title="Editions">
<link rel="prev" href="/products/server" title="Foo Server">
<link rel="canonical" href="http://www.example.com/?page=server-faq">
<link rev="subsection" href="/products/server" title="Foo Server">

菜单

menu()辅助工具用于从导航容器中渲染菜单。默认情况下,菜单将使用HTML ULLI标签进行渲染,但辅助工具还允许使用部分视图脚本。

菜单辅助工具中的方法

以下为renderMenu()方法所认可的选择项

基本用法

此示例显示了如何从视图辅助工具中注册/找到的容器中渲染菜单。请注意,页面根据可见性和ACL进行过滤。

在视图脚本或布局中

<?= $this->navigation()->menu()->render() ?>

<?= $this->navigation()->menu() ?>

输出

<ul class="navigation">
    <li>
        <a title="Go Home" href="/">Home</a>
    </li>
    <li class="active">
        <a href="/products">Products</a>
        <ul>
            <li class="active">
                <a href="/products/server">Foo Server</a>
                <ul>
                    <li class="active">
                        <a href="/products/server/faq">FAQ</a>
                    </li>
                    <li>
                        <a href="/products/server/editions">Editions</a>
                    </li>
                    <li>
                        <a href="/products/server/requirements">System Requirements</a>
                    </li>
                </ul>
            </li>
            <li>
                <a href="/products/studio">Foo Studio</a>
                <ul>
                    <li>
                        <a href="/products/studio/customers">Customer Stories</a>
                    </li>
                    <li>
                        <a href="/products/studio/support">Support</a>
                    </li>
                </ul>
            </li>
        </ul>
    </li>
    <li>
        <a title="About us" href="/company/about">Company</a>
        <ul>
            <li>
                <a href="/company/about/investors">Investor Relations</a>
            </li>
            <li>
                <a class="rss" href="/company/news">News</a>
                <ul>
                    <li>
                        <a href="/company/news/press">Press Releases</a>
                    </li>
                    <li>
                        <a href="/archive">Archive</a>
                    </li>
                </ul>
            </li>
        </ul>
    </li>
    <li>
        <a href="/community">Community</a>
        <ul>
            <li>
                <a href="/community/account">My Account</a>
            </li>
            <li>
                <a class="external" href="http://forums.example.com/">Forums</a>
            </li>
        </ul>
    </li>
</ul>

直接调用renderMenu()

此示例显示了如何通过直接调用renderMenu()并指定选项来渲染未在视图辅助工具中注册的菜单。

<?php
// render only the 'Community' menu
$community = $this->navigation()->findOneByLabel('Community');
$options = [
    'indent'  => 16,
    'ulClass' => 'community'
];
echo $this->navigation()
          ->menu()
          ->renderMenu($community, $options);
?>

输出

<ul class="community">
    <li>
        <a href="/community/account">My Account</a>
    </li>
    <li>
        <a class="external" href="http://forums.example.com/">Forums</a>
    </li>
</ul>

渲染最深的活跃菜单

此示例显示了renderSubMenu()将如何渲染活跃分支的最深子菜单。

调用renderSubMenu($container, $ulClass, $indent)相当于调用renderMenu($container, $options)并使用以下选项

[
    'ulClass'          => $ulClass,
    'indent'           => $indent,
    'minDepth'         => null,
    'maxDepth'         => null,
    'onlyActiveBranch' => true,
    'renderParents'    => false,
]

renderSubMenu方法的使用

<?= $this->navigation()
    ->menu()
    ->renderSubMenu(null, 'sidebar', 4) ?>

如果'FAQ'或'Foo Server'是活跃的,输出将相同

<ul class="sidebar">
    <li class="active">
        <a href="/products/server/faq">FAQ</a>
    </li>
    <li>
        <a href="/products/server/editions">Editions</a>
    </li>
    <li>
        <a href="/products/server/requirements">System Requirements</a>
    </li>
</ul>

以最大深度渲染

<?= $this->navigation()
    ->menu()
    ->setMaxDepth(1) ?>

输出

<ul class="navigation">
    <li>
        <a title="Go Home" href="/">Home</a>
    </li>
    <li class="active">
        <a href="/products">Products</a>
        <ul>
            <li class="active">
                <a href="/products/server">Foo Server</a>
            </li>
            <li>
                <a href="/products/studio">Foo Studio</a>
            </li>
        </ul>
    </li>
    <li>
        <a title="About us" href="/company/about">Company</a>
        <ul>
            <li>
                <a href="/company/about/investors">Investor Relations</a>
            </li>
            <li>
                <a class="rss" href="/company/news">News</a>
            </li>
        </ul>
    </li>
    <li>
        <a href="/community">Community</a>
        <ul>
            <li>
                <a href="/community/account">My Account</a>
            </li>
            <li>
                <a class="external" href="http://forums.example.com/">Forums</a>
            </li>
        </ul>
    </li>
</ul>

以最小深度渲染

<?= $this->navigation()
    ->menu()
    ->setMinDepth(1) ?>

输出

<ul class="navigation">
    <li class="active">
        <a href="/products/server">Foo Server</a>
        <ul>
            <li class="active">
                <a href="/products/server/faq">FAQ</a>
            </li>
            <li>
                <a href="/products/server/editions">Editions</a>
            </li>
            <li>
                <a href="/products/server/requirements">System Requirements</a>
            </li>
        </ul>
    </li>
    <li>
        <a href="/products/studio">Foo Studio</a>
        <ul>
            <li>
                <a href="/products/studio/customers">Customer Stories</a>
            </li>
            <li>
                <a href="/products/studio/support">Support</a>
            </li>
        </ul>
    </li>
    <li>
        <a href="/company/about/investors">Investor Relations</a>
    </li>
    <li>
        <a class="rss" href="/company/news">News</a>
        <ul>
            <li>
                <a href="/company/news/press">Press Releases</a>
            </li>
            <li>
                <a href="/archive">Archive</a>
            </li>
        </ul>
    </li>
    <li>
        <a href="/community/account">My Account</a>
    </li>
    <li>
        <a class="external" href="http://forums.example.com/">Forums</a>
    </li>
</ul>

仅渲染活跃分支

<?= $this->navigation()
    ->menu()
    ->setOnlyActiveBranch(true) ?>

输出

<ul class="navigation">
    <li class="active">
        <a href="/products">Products</a>
        <ul>
            <li class="active">
                <a href="/products/server">Foo Server</a>
                <ul>
                    <li class="active">
                        <a href="/products/server/faq">FAQ</a>
                    </li>
                    <li>
                        <a href="/products/server/editions">Editions</a>
                    </li>
                    <li>
                        <a href="/products/server/requirements">System Requirements</a>
                    </li>
                </ul>
            </li>
        </ul>
    </li>
</ul>

仅渲染具有最小深度的活跃分支

<?= $this->navigation()
    ->menu()
    ->setOnlyActiveBranch(true)
    ->setMinDepth(1) ?>

输出

<ul class="navigation">
    <li class="active">
        <a href="/products/server">Foo Server</a>
        <ul>
            <li class="active">
                <a href="/products/server/faq">FAQ</a>
            </li>
            <li>
                <a href="/products/server/editions">Editions</a>
            </li>
            <li>
                <a href="/products/server/requirements">System Requirements</a>
            </li>
        </ul>
    </li>
</ul>

仅渲染具有最大深度的活动分支

<?= $this->navigation()
    ->menu()
    ->setOnlyActiveBranch(true)
    ->setMaxDepth(1) ?>

输出

<ul class="navigation">
    <li class="active">
        <a href="/products">Products</a>
        <ul>
            <li class="active">
                <a href="/products/server">Foo Server</a>
            </li>
            <li>
                <a href="/products/studio">Foo Studio</a>
            </li>
        </ul>
    </li>
</ul>

仅渲染具有最大深度和没有父级的活动分支

<?= $this->navigation()
    ->menu()
    ->setOnlyActiveBranch(true)
    ->setRenderParents(false)
    ->setMaxDepth(1) ?>

输出

<ul class="navigation">
    <li class="active">
        <a href="/products/server">Foo Server</a>
    </li>
    <li>
        <a href="/products/studio">Foo Studio</a>
    </li>
</ul>

使用部分视图脚本渲染自定义菜单

本例演示了如何使用部分视图脚本渲染自定义菜单。通过调用setPartial(),您可以在调用render()时指定一个部分视图脚本,当指定部分视图时,该方法将代理到renderPartial()方法。

renderPartial()方法将容器分配给具有键container的视图。

在布局中

$this->navigation()->menu()->setPartial('my-module/partials/menu');
echo $this->navigation()->menu()->render();

module/MyModule/view/my-module/partials/menu.phtml

foreach ($this->container as $page) {
    echo $this->navigation()->menu()->htmlify($page) . PHP_EOL;
}

输出

<a title="Go Home" href="/">Home</a>
<a href="/products">Products</a>
<a title="About us" href="/company/about">Company</a>
<a href="/community">Community</a>

在部分视图脚本中使用额外参数

从版本2.6.0开始,您可以将自定义变量分配给部分脚本。

在布局中

// Set partial
$this->navigation()->menu()->setPartial('my-module/partials/menu');

// Output menu
echo $this->navigation()->menu()->renderPartialWithParams(
    [
        'headline' => 'Links',
    ]
);

module/MyModule/view/my-module/partials/menu.phtml

<h1><?= $headline ?></h1>

<?php
foreach ($this->container as $page) {
    echo $this->navigation()->menu()->htmlify($page) . PHP_EOL;
}
?>

输出

<h1>Links</h1>
<a title="Go Home" href="/">Home</a>
<a href="/products">Products</a>
<a title="About us" href="/company/about">Company</a>
<a href="/community">Community</a>

在部分视图脚本中使用菜单选项

在布局中

// Set options
$this->navigation()->menu()
    ->setUlClass('my-nav')
    ->setPartial('my-module/partials/menu');

// Output menu
echo $this->navigation()->menu()->render();

module/MyModule/view/my-module/partials/menu.phtml

<div class"<?= $this->navigation()->menu()->getUlClass() ?>">
    <?php
    foreach ($this->container as $page) {
        echo $this->navigation()->menu()->htmlify($page) . PHP_EOL;
    }
    ?>
</div>

输出

<div class="my-nav">
    <a title="Go Home" href="/">Home</a>
    <a href="/products">Products</a>
    <a title="About us" href="/company/about">Company</a>
    <a href="/community">Community</a>
</div>

在部分视图脚本中使用访问控制列表(ACL)

如果您想在部分视图脚本中使用ACL,那么您将不得不手动检查对页面的访问权限。

module/MyModule/view/my-module/partials/menu.phtml

foreach ($this->container as $page) {
    if ($this->navigation()->accept($page)) {
        echo $this->navigation()->menu()->htmlify($page) . PHP_EOL;
    }
}

视图辅助器 - 网站地图

sitemap()辅助器用于生成XML网站地图,该地图由Sitemaps XML格式定义。关于网站地图的更多信息,请参阅维基百科上的网站地图

默认情况下,网站地图辅助器使用网站地图验证器验证每个渲染的元素。这可以通过调用$helper->setUseSitemapValidators(false)来禁用。

网站地图XML元素

仅在启用时进行验证

如果您禁用网站地图验证器,则不会验证自定义属性(见表格)。

网站地图辅助器还支持对生成的网站地图进行Sitemap XSD模式验证。默认情况下,这是禁用的,因为它将需要请求模式文件。可以通过$helper->setUseSchemaValidation(true)来启用。

网站地图辅助器中的方法

基本用法

本例演示了如何根据我们上面所做的设置渲染XML网站地图。

// In a view script or layout:

// format output
$this->navigation()
      ->sitemap()
      ->setFormatOutput(true); // default is false

// Other possible methods:
// ->setUseXmlDeclaration(false);             // default is true
// ->setServerUrl('http://my.otherhost.com'); // default is to detect automatically

// print sitemap
echo $this->navigation()->sitemap();

注意如何过滤掉不可见的页面或与视图辅助器不兼容的ACL角色的页面

<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="https://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>http://www.example.com/</loc>
  </url>
  <url>
    <loc>http://www.example.com/products</loc>
  </url>
  <url>
    <loc>http://www.example.com/products/server</loc>
  </url>
  <url>
    <loc>http://www.example.com/products/server/faq</loc>
  </url>
  <url>
    <loc>http://www.example.com/products/server/editions</loc>
  </url>
  <url>
    <loc>http://www.example.com/products/server/requirements</loc>
  </url>
  <url>
    <loc>http://www.example.com/products/studio</loc>
  </url>
  <url>
    <loc>http://www.example.com/products/studio/customers</loc>
  </url>
  <url>
    <loc>http://www.example.com/products/studio/support</loc>
  </url>
  <url>
    <loc>http://www.example.com/company/about</loc>
  </url>
  <url>
    <loc>http://www.example.com/company/about/investors</loc>
  </url>
  <url>
    <loc>http://www.example.com/company/news</loc>
  </url>
  <url>
    <loc>http://www.example.com/company/news/press</loc>
  </url>
  <url>
    <loc>http://www.example.com/archive</loc>
  </url>
  <url>
    <loc>http://www.example.com/community</loc>
  </url>
  <url>
    <loc>http://www.example.com/community/account</loc>
  </url>
  <url>
    <loc>http://forums.example.com/</loc>
  </url>
</urlset>

不使用ACL角色进行渲染

不使用ACL角色渲染网站地图(应该过滤掉/community/account

echo $this->navigation()->sitemap()
    ->setFormatOutput(true)
    ->setRole();

输出

<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="https://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>http://www.example.com/</loc>
  </url>
  <url>
    <loc>http://www.example.com/products</loc>
  </url>
  <url>
    <loc>http://www.example.com/products/server</loc>
  </url>
  <url>
    <loc>http://www.example.com/products/server/faq</loc>
  </url>
  <url>
    <loc>http://www.example.com/products/server/editions</loc>
  </url>
  <url>
    <loc>http://www.example.com/products/server/requirements</loc>
  </url>
  <url>
    <loc>http://www.example.com/products/studio</loc>
  </url>
  <url>
    <loc>http://www.example.com/products/studio/customers</loc>
  </url>
  <url>
    <loc>http://www.example.com/products/studio/support</loc>
  </url>
  <url>
    <loc>http://www.example.com/company/about</loc>
  </url>
  <url>
    <loc>http://www.example.com/company/about/investors</loc>
  </url>
  <url>
    <loc>http://www.example.com/company/news</loc>
  </url>
  <url>
    <loc>http://www.example.com/company/news/press</loc>
  </url>
  <url>
    <loc>http://www.example.com/archive</loc>
  </url>
  <url>
    <loc>http://www.example.com/community</loc>
  </url>
  <url>
    <loc>http://forums.example.com/</loc>
  </url>
</urlset>

使用最大深度进行渲染

使用最大深度为1渲染网站地图。

echo $this->navigation()->sitemap()
    ->setFormatOutput(true)
    ->setMaxDepth(1);

输出

<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="https://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>http://www.example.com/</loc>
  </url>
  <url>
    <loc>http://www.example.com/products</loc>
  </url>
  <url>
    <loc>http://www.example.com/products/server</loc>
  </url>
  <url>
    <loc>http://www.example.com/products/studio</loc>
  </url>
  <url>
    <loc>http://www.example.com/company/about</loc>
  </url>
  <url>
    <loc>http://www.example.com/company/about/investors</loc>
  </url>
  <url>
    <loc>http://www.example.com/company/news</loc>
  </url>
  <url>
    <loc>http://www.example.com/community</loc>
  </url>
  <url>
    <loc>http://www.example.com/community/account</loc>
  </url>
  <url>
    <loc>http://forums.example.com/</loc>
  </url>
</urlset>

默认使用UTF-8编码

默认情况下,laminas-view使用UTF-8作为其默认编码。如果您想在Sitemap中使用其他编码,您需要做三件事

  1. 创建一个自定义渲染器并实现getEncoding()方法。
  2. 创建一个自定义渲染策略,该策略将返回您的自定义渲染器实例。
  3. ViewEvent中附加自定义策略。

请参阅HeadStyle文档中的示例,了解如何实现这一点。

许可

本软件包使用MIT许可。

请参阅LICENSE.md