Zend Framework 2: 导航系统

5
在我的控制器中,我创建了导航对象并将其传递给视图。
$navigation = new \Zend\Navigation\Navigation(array(
    array(
            'label' => 'Album',
            'controller' => 'album',
            'action' => 'index',
            'route' => 'album',
        ),
    ));

他们正在尝试使用它。
<?php echo $this->navigation($this->navigation)->menu() ?>

我收到了以下错误提示:

致命错误:Zend\Navigation\Exception\DomainException:Zend\Navigation\Page\Mvc::getHref无法执行,因为Zend\View\Helper\Navigation\AbstractHelper.php的构成中没有Zend\Mvc\Router\RouteStackInterface实例。位于第471行。

但是,我在布局中使用的导航(navigation),就像这里所写的那样。我的错误在哪里?

谢谢。

3个回答

10

问题是缺少路由器(或更精确地说,Zend\Mvc\Router\RouteStackInterface)。 路由堆栈是路由的集合,可以使用路由名称将其转换为URL。 基本上,它接受路由名称并为您创建URL:

$url = $routeStack->assemble('my/route');

这种情况也发生在Zend\Navigation的MVC页面中。该页面具有一个route参数,当存在路由器时,该页面会组装自己的URL(或者按照Zend\Navigation术语说,是一个href)。如果您不提供路由器,则无法组装路由,因此会引发异常。

您必须在导航的每个页面中注入路由器:

$navigation = new Navigation($config);
$router     = $serviceLocator->get('router');

function injectRouter($navigation, $router) {
  foreach ($navigation->getPages() as $page) {
    if ($page instanceof MvcPage) {
      $page->setRouter($router);
    }

    if ($page->hasPages()) {
      injectRouter($page, $router);
    }
  }
}

正如你所看到的,这是一个递归函数,将路由器注入到每个页面中。很繁琐!因此,有一个工厂可以为您完成这项工作。有四个简单的步骤可以实现这一点。

第一步

首先将导航配置放在模块配置中。就像你有一个default导航一样,你可以创建第二个secondary导航。

'navigation' => array(
    'secondary' => array(
        'page-1' => array(
            'label' => 'First page',
            'route' => 'route-1'
        ),
        'page-2' => array(
            'label' => 'Second page',
            'route' => 'route-2'
        ),
    ),
),

您已经有到达第一页(route-1)和第二页(route-2)的路由。

步骤二

一个工厂将把这个转换成导航对象结构,您需要先创建一个该类。在您的MyModule/Navigation/Service目录中创建一个名为SecondaryNavigationFactory.php的文件。

namespace MyModule\Navigation\Service;

use Zend\Navigation\Service\DefaultNavigationFactory;

class SecondaryNavigationFactory extends DefaultNavigationFactory
{
    protected function getName()
    {
        return 'secondary';
    }
}

注意这里我将名称secondary设置为与您的导航键相同。

第三步

您必须将此工厂注册到服务管理器中。然后,该工厂就可以工作并将配置文件转换为Zend\Navigation对象。您可以在module.config.php文件中执行此操作:

'service_manager' => array(
    'factories' => array(
        'secondary_navigation' => 'MyModule\Navigation\Service\SecondaryNavigationFactory'
    ),
)

看这里,我创建了一个名为secondary_navigation的服务,在这个工厂函数中,会返回一个Zend\Navigation实例。如果你现在调用$sm->get('secondary_navigation'),你将会得到一个Zend\Navigation\Navigation对象。

第四步

告诉视图辅助器使用这个导航而不是默认的。导航视图辅助程序接受一个"navigation"参数,您可以在其中指定要使用哪个导航。在这种情况下,服务管理器有一个名为secondary_navigation的服务,这就是我们需要的那个。

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

现在你将会在这个视图助手中使用导航secondary

声明:这个答案与我在这个问题中回答的相同


这是一个很好的例子。它可以正常工作,直到我想使用视图部分进行渲染。我正在将其用于我的主导航,但这不应该有影响。这是我正在使用的:echo $this->navigation('navigation')->menu()->setPartial(array('navigation.phtml', 'Application'));致命错误:Zend\ServiceManager\Exception\ServiceNotFoundException: Zend\ServiceManager\ServiceManager::get无法获取或创建菜单实例,在/myapp/vendor/zendframework/zendframework/library/Zend/View/Helper/Navigation/AbstractHelper.php的第471行。 - Jeremy Hicks

2

顺便提一下,如果您定义了一个路由,而且控制器和操作是可变的片段,则不需要定义controlleraction,只需定义一个route即可。


你说得对,感谢您的评论。但是如果这样做,公告页面错误仍然存在。当代码运行时,唯一的选项是:$navigation = new \Zend\Navigation\Navigation(array( array( 'label' => 'Album', 'uri'=>'/' ), )); 当URL直接设置时。 - Eremite
不太清楚,但是你的 module.php 文件中有这段代码吗?$application = $e->getApplication(); $eventManager = $application->getEventManager(); $moduleRouteListener = new ModuleRouteListener(); $moduleRouteListener->attach($eventManager); - Andreas Linden
是的,在Module.php文件中的onBootstrap方法中,我有完全相同的代码。有趣的是,我的视图中的url视图助手可以正常工作。代码$this->url('album/default', array('controller'=>'album', 'action'=>'edit', 'id' => $id))非常好地运行,并在页面上显示链接。目前还不清楚它会干扰菜单的正确显示。如果有任何想法,我很乐意听取。谢谢。 - Eremite

0
问题确实是路由器无法在没有路由器的情况下解析。我希望导航类能够解决这个问题,但显然你必须自己解决它。我刚刚编写了一个视图助手来引入MVC页面中的路由器。
以下是我在视图中使用它的方式:
$navigation = $this->navigation();
$navigation->addPage(
    array(
        'route' => 'language',
        'label' => 'language.list.nav'
    )
);
$this->registerNavigationRouter($navigation);
echo $navigation->menu()->render();

视图助手:

<?php
namespace JarJar\View\Helper;

use Zend\View\Helper\AbstractHelper;
use Zend\View\Helper\Navigation;
use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Zend\Navigation\Page\Mvc;

class RegisterNavigationRouter extends AbstractHelper implements ServiceLocatorAwareInterface
{
    protected $serviceLocator;

    public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
    {
        $this->serviceLocator = $serviceLocator;
    }

    public function getServiceLocator()
    {
        return $this->serviceLocator;
    }

    public function __invoke(Navigation $navigation)
    {
        $router = $this->getRouter();
        foreach ($navigation->getPages() as $page) {
            if ($page instanceof Mvc) {
                $page->setRouter($router);
            }
        }
    }

    protected function getRouter()
    {
        $router = $this->getServiceLocator()->getServiceLocator()->get('router');
        return $router;
    }
}

不要忘记在您的配置中添加视图助手作为可调用实例:

'view_helpers' => array(
    'invokables' => array(
        'registerNavigationRouter' => 'JarJar\View\Helper\RegisterNavigationRouter'
    )
),

这不是一个很好的解决方案,但它能够工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接