【问题标题】:ZF2 - Add pages to navigation in the controllerZF2 - 将页面添加到控制器中的导航
【发布时间】:2015-11-03 23:12:34
【问题描述】:

在我的项目中,我有一个导航,它是使用默认工厂从 config.php 文件中的数组创建的。我想将子页面添加到控制器中的当前页面。

class IndexController extends AbstractActionController {
    public function newpageAction() {
        $navigation = $this->getServiceLocator()->get('navigation');
        $currentPage = $navigation->findById('index');

        $options = array(
            'id'         => 'newpage',
            'label'      => 'New Page',
            'route'      => 'my-route',
            'controller' => 'index',
            'action'     => 'newpage',
            'active'     => true,
        );
        $newpage = new \Zend\Navigation\Page\Mvc($options);

        $currentPage->addPage($newpage);
    }
}

页面添加成功,但我尝试使用页面的 getHref() 方法在面包屑视图中创建页面的 url:

<?php foreach($this->pages as $page) {?>
<li>
    <a href="<?php echo $page->getHref();?>"><?php echo $page->getLabel();?></a>
</li>
<?php }?>

但新添加的页面出现以下错误:

Additional information:
Zend\Navigation\Exception\DomainException

File:
\vendor\zendframework\zendframework\library\Zend\Navigation\Page\Mvc.php:198

Message:

Zend\Navigation\Page\Mvc::getHref cannot execute as no Zend\Mvc\Router\RouteStackInterface instance is composed

我想问题在于我创建页面并将其添加到导航的方式。还有其他方法可以做到这一点或我如何解决此错误?

我想在控制器中而不是在配置文件中添加第三级之后的页面,因为页面的 url 中有参数并且标签是动态的。 欢迎以任何其他方式完成此任务的任何建议。

【问题讨论】:

    标签: zend-framework2


    【解决方案1】:

    您可以添加默认路由器。

    \Zend\Navigation\Page\Mvc::setDefaultRouter ($this->getServiceLocator ()->get ('router'));
    

    【讨论】:

    • 非常感谢!像魅力一样工作。
    【解决方案2】:

    错误是由于MVC 页面具有未满足的依赖关系(路由器)。它是 the factory's job to inject these components(取决于 URI 或 MVC 类型)。

    为了确保每个 MVC 页面都注入了路由器,请创建 一个新工厂,然后使用另一个已经提供的工厂 Zend\Navigation\Service\ConstructedNavigationFactory 创建您自己的导航容器并返回它的页面。在您的示例中,这将只是一页。


    编辑

    如果您在控制器中添加导航页面,而您不知道newpageAction()之前的页面配置;您可以扩展该类以允许在控制器中设置配置。

    例如

    public function MyCustomNavFactory extends ConstructedNavigationFactory
    {
      // make the config optional
      public function __construct($config = array())
      {
        $this->config = $config;
      }
      // Allow config to be set outside the class
      public function setConfig($config)
      {
        $this->config = $config;
      }
    
    }
    

    Module.php

    // Module
    public function getServiceConfig() {
      return array(
        'invokables' => array(
          // Create the factory as an invokable (as there are no __construct args)
          'MyCustomNavFactory' => 'App\Navigation\Service\MyCustomNavFactory'
        ),
      );
    }
    

    控制器调用将只是简单地使用

    // Controller
    public function newpageAction()
    {
      $serviceManager = $this->getServiceLocator();
      $navigation = $serviceManager->get('MyCustomNavFactory');
    
      $options = array(
        'id'         => 'newpage',
        'label'      => 'New Page',
        'route'      => 'my-route',
        'controller' => 'index',
        'action'     => 'newpage',
        'active'     => true,
      );
      $navigation->setConfig($options);
      $pages = $navigation->getPages($serviceManager);
    }
    

    【讨论】:

    • 感谢 AlexP 的回答。现在我明白为什么 url 生成不起作用了。但是在您的解决方案中,页面的 $options 在工厂中,如果我想创建其他自定义页面,我想我应该创建另一个工厂。是否有另一种方法可以为每个自定义页面提供 $options。我想,我可以直接在控制器动作中使用 ConstructedNavigationFactory 还是这是一个糟糕的设计?
    • @ElenaSlavcheva 我已经更新了我的答案 - 在控制器操作之前不知道 $options 会改变方法。我确信有一个“更清洁”的解决方案(比如将控制器中的上述代码移动到服务层);我个人希望配置中的所有“新页面”都在某个地方,并为每个不同的“新页面”建立一个工厂,这将避免可能的代码重复。
    【解决方案3】:

    @AlexPanswer 是正确的。

    但是控制器动作出现错误,因为当他使用ServiceLocator 调用自定义工厂时,将获得AbstractContainer 对象类型的对象,因为ServiceLocator 将在您的自定义工厂中调用createService 方法( MyCustomNavFactory) 扩展了 AbstractNavigationFactory 所以下一行将调用 setConfig 方法到 AbstractContainer 对象不是你的自定义工厂 (MyCustomNavFactory)。

    从控制器动作设置面包屑配置的正确方法是:

    // Controller
    public function newpageAction()
    {
      $serviceManager    = $this->getServiceLocator();
      $navigationFactory = new MyCustomNavFactory();
    
      $options = array(
        'id'         => 'newpage',
        'label'      => 'New Page',
        'route'      => 'my-route',
        'controller' => 'index',
        'action'     => 'newpage',
        'active'     => true,
      );
      $navigationFactory->setConfig($options);
      $pages = $navigationFactory->getPages($serviceManager);
    }
    

    从自定义工厂中移除 setConfig 方法并使用它的构造函数设置配置

    // custom Factory
    public function MyCustomNavFactory extends ConstructedNavigationFactory
    {
      // make the config optional
      public function __construct($config = array())
      {
        parent::__construct($config);
      }
    } 
    

    那么控制器将是:

    // Controller
    public function newpageAction()
    {
      $serviceManager = $this->getServiceLocator();    
      $options = array(
         array(
           'id'         => 'newpage',
           'label'      => 'New Page',
           'route'      => 'my-route',
           'controller' => 'index',
           'action'     => 'newpage',
           'active'     => true,
        )
      );
      $navigationFactory = new MyCustomNavFactory($options);
      $pages = $navigationFactory->getPages($serviceManager);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多