ZF2:如何在自定义路径中获得Zend \ Navigation?

时间:2012-11-10 16:56:47

标签: php zend-framework2 zend-navigation zend-router

我有自定义路由器,我必须访问此自定义路由器中的Zend\Navigation。我在谷歌搜索,询问和搜索,没有结果:/

我只需要在Alias :: match函数中使用Zend \ Navigation查找带有'link'参数的节点。

这是我的module.config.php:

'navigation' => array(
        'default' => array(
            'account' => array(
                'label' => 'Account',
                'route' => 'node',
                'pages' => array(
                    'home' => array(
                        'label' => 'Dashboard',
                        'route' => 'node',
                        'params' => array(
                                    'id' => '1',
                                    'link' => '/about/gallery'
                                    ),
                    ),
                ),
            ),
        ),
    ),
[...]

这是我的Alias课程:

// file within ModuleName/src/ModuleName/Router/Alias.php
namespace Application\Router;

use Traversable;
use Zend\Mvc\Router\Exception;
use Zend\Stdlib\ArrayUtils;
use Zend\Stdlib\RequestInterface as Request;
use Zend\Mvc\Router\Http;
use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceLocatorInterface;

class Alias extends Http\Segment implements ServiceLocatorAwareInterface
{

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

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

    public function match(Request $request, $pathOffset = null)
    {
        [...]

        return parent::match($request, $pathOffset);        
    }

}

编辑:

现在我知道我应该将服务管理器注入我的自定义路由器。如果你知道怎么做,请告诉我:))

编辑:

好吧,它不是自定义路由器而是路由。我的错。我正在谈论#zftalk irc chanell和AliasSegment类应该实现ServiceLocatorAwareInterface。好的我已经尝试过但现在又出现了另一个问题。

<击>

setServiceLocator函数中,我无法获得service locator。它返回null对象,但$serviceLocator是类Zend\Mvc\Router\RoutePluginManager

public function setServiceLocator(ServiceLocatorInterface $serviceLocator){
    $sl = $serviceLocator->getServiceLocator();
    var_dump($sl); // NULL
}

如何从中获取Zend导航的任何想法?

EDITED

对应@mmmshuddup所说的,我已经改变了我的自定义路由器类。 (新版本在上面)。同样在我的Module.php onBootstrap函数中,我添加了这一行:

$sm->setFactory('Navigation', 'Zend\Navigation\Service\DefaultNavigationFactory', true);

导航工作并在route之前实例化,因此它应该在我的Alias类中可见,但事实并非如此。

我已经在match类中添加了Alias这一行:

$servicesArray = $this->getServiceLocator()->getRegisteredServices();

$servicesArray几乎是空的。没有服务,没有工厂。在设置新工厂(如上所述)之后插入onBootstrap的同一行返回带有navigation和其他服务的数组。

问题是:如何与我的自定义路由器共享此阵列(或ServiceManager):Alias

我不得不说,我想要做的就是在ZF1中做到这一点非常容易。

修改

我找到了解决方案。答案如下:

2 个答案:

答案 0 :(得分:2)

这是因为对象本身实际上没有any properties declared。但如果你这样做:

echo get_class($sl);

您会看到它确实是Zend\ServiceManager\ServiceManager

的一个实例

您应该能够通过以下操作获取导航实例:

$nav = $sl->get('Navigation');

<击>

编辑:

我只是注意到你的代码位置错误。您正在 getServiceLocator()上调用$serviceLocator ,这已经是其中的实例。您也可以在 setServiceLocator() 中调用它。你应该把它改成:

// EDIT - file within ModuleName/src/Router/Alias.php
namespace Application\Router;

use Traversable;
use Zend\Mvc\Router\Exception;
use Zend\Stdlib\ArrayUtils;
use Zend\Stdlib\RequestInterface as Request;
use Zend\Mvc\Router\Http;

class Alias extends Http\Segment implements ServiceLocatorAwareInterface
{
    public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
    {
        $this->serviceLocator = $serviceLocator;
        return $this;
    }

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

    public function match(Request $request, $pathOffset = null)
    {
        $nav = $this->getServiceLocator()->get('Navigation');
        // ...
        return parent::match($request, $pathOffset);
    }
}

答案 1 :(得分:1)

我找到了解决方案,但我认为这是不优雅的解决方案。然而一切都很完美。如果有人知道这个解决方案的缺点,请评论这个答案或添加另一个,更好。我不得不修改@mmmshuddup的想法(you can read the conversation)。

首先,不再需要在自定义路由类中实现ServiceLocatorAwareInterface

Module.php函数中的onBootstrap

    $app = $e->getApplication();
    $sm  = $app->getServiceManager();
    $sm->get('translator');
    $eventManager        = $e->getApplication()->getEventManager();
    $moduleRouteListener = new ModuleRouteListener();
    $moduleRouteListener->attach($eventManager);

    $sm->setFactory('Navigation', 
                    'Zend\Navigation\Service\DefaultNavigationFactory', true);

    $nav = $sm->get('Navigation');
    $alias = $sm->get('Application\Router\Alias');
    $alias->setNavigation($nav);

首先我们在Navigation中实例化ServiceManager工厂,然后我们的自定义路线。之后,我们可以使用setNavigation函数将Navigation类传递到自定义路径。 要完成我们的自定义路由的实例化,我们需要在同一文件中的getServiceConfig

    return array(
        'factories' => array(
            'Application\Router\Alias' => function($sm) {
                $alias = new \Application\Router\Alias('/node[/:id]');
                return $alias;
            },
            'db_adapter' =>  function($sm) {
                $config = $sm->get('Configuration');
                $dbAdapter = new \Zend\Db\Adapter\Adapter($config['db']);
                return $dbAdapter;
            },
        )
    );

这是一个棘手的部分。这个例子是暂时的。在路由时,这个类将再次被实例化,这就是为什么,我认为它不是很优雅。我们必须在构造函数中插入参数,但此时此参数的值并不重要。

自定义路线类:

// file within ModuleName/src/ModuleName/Router/Alias.php
namespace Application\Router;

use Traversable;
use Zend\Mvc\Router\Exception;
use Zend\Stdlib\ArrayUtils;
use Zend\Stdlib\RequestInterface as Request;
use Zend\Mvc\Router\Http;

class Alias extends Http\Segment
{

    private static $_navigation = null;

    public function match(Request $request, $pathOffset = null)
    {
        //some logic here

        //get Navigation
        $nav = self::$_navigation;

        return parent::match($request, $pathOffset);
    }

    public function setNavigation($navigation){
        self::$_navigation = $navigation;
    }

}

因为第一个实例是临时的,我们必须在静态变量中收集Navigation类。这很可怕,但效果很好。也许有一种方法只将它实例化一次并在路由配置中得到它的实例,但此时这是我的问题的最佳答案。足够简单,工作正常。