如何在视图中获取匹配的路线名称 - Zend Expressive

tas*_*ski 2 php zend-framework zend-framework3 fastroute mezzio

我知道我可以生成传递路由名称的 URL

<?php echo $this->url('route-name') #in view file ?>
Run Code Online (Sandbox Code Playgroud)

但我可以获得相反方向的信息吗?我需要从当前的 URL/URI 获取路由名称。

真实情况是:我有layout.phtml,其中顶部菜单(html)。菜单中的当前链接需要用 css 类标记。所以,我需要的例子是:

<?php // in layout.phtml file
  $index_css   = $this->getRouteName() == 'home-page' ? 'active' : 'none'; 
  $about_css   = $this->getRouteName() == 'about'     ? 'active' : 'none'; 
  $contact_css = $this->getRouteName() == 'contact'   ? 'active' : 'none';  
?>
Run Code Online (Sandbox Code Playgroud)

我正在使用快速路线,但我对任何解决方案都很感兴趣。解决方案不必位于视图文件中。

tas*_*ski 5

根据我的研究,公共方法getMatchedRouteName()中的RouteResult实例中有这样的信息。问题是如何从视图到达这个实例。

我们知道我们可以获取 RouteResult,但是可以从中间件的 __invoke() 方法中的 Request 对象获取。

public function __invoke($request, $response, $next){
    # instance of RouteResult
    $routeResult = $request->getAttribute('Zend\Expressive\Router\RouteResult');
    $routeName   = $routeResult->getMatchedRouteName();
    // ... 
}
Run Code Online (Sandbox Code Playgroud)

正如 @timdev 所建议的,我们将在现有的帮助器UrlHelper中找到灵感,并在自定义视图帮助器中进行几乎相同的实现

简而言之,我们将创建 2 个类。

  1. CurrentUrlHelper具有方法setRouteResult()
  2. CurrentUrlMiddleware__invoke($req, $res, $next)

我们将在 CurrentUrlMiddleware 中注入 CurrentUrlHelper,并在 __invoke() 方法中使用适当的 RouteResult 实例调用CurrentUrlHelper::setRouteResult()。稍后我们可以将 CurrentUrlHelper 与其中的 RouteResult 实例一起使用。这两个类也应该有一个工厂。

class CurrentUrlMiddlewareFactory {
    public function __invoke(ContainerInterface $container) {
        return new CurrentUrlMiddleware(
            $container->get(CurrentUrlHelper::class)
        );
    }
}

class CurrentUrlMiddleware {
    private $currentUrlHelper;

    public function __construct(CurrentUrlHelper $currentUrlHelper) {
        $this->currentUrlHelper = $currentUrlHelper;
    }

    public function __invoke($request, $response, $next = null) {
        $result = $request->getAttribute('Zend\Expressive\Router\RouteResult');
        $this->currentUrlHelper->setRouteResult($result);

        return $next($request, $response); # continue with execution
    }
}
Run Code Online (Sandbox Code Playgroud)

还有我们的新帮手:

class CurrentUrlHelper {
    private $routeResult;

    public function __invoke($name) {
        return $this->routeResult->getMatchedRouteName() === $name;
    }

    public function setRouteResult(RouteResult $result) {
        $this->routeResult = $result;
    }
}


class CurrentUrlHelperFactory{
    public function __invoke(ContainerInterface $container){
        # pull out CurrentUrlHelper from container!
        return $container->get(CurrentUrlHelper::class);
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我们只需要在配置中注册新的视图助手和中间件:

依赖项.global.php

'dependencies' => [
    'invokables' => [
        # dont have any constructor! 
        CurrentUrlHelper::class => CurrentUrlHelper::class, 
    ],
]
Run Code Online (Sandbox Code Playgroud)

中间件-pipeline.global.php

'factories' => [
    CurrentUrlMiddleware::class => CurrentUrlMiddlewareFactory::class,
], 
'middleware' => [
    Zend\Expressive\Container\ApplicationFactory::ROUTING_MIDDLEWARE,
    Zend\Expressive\Helper\UrlHelperMiddleware::class,
    CurrentUrlMiddleware::class,         # Our new Middleware
    Zend\Expressive\Container\ApplicationFactory::DISPATCH_MIDDLEWARE,
],
Run Code Online (Sandbox Code Playgroud)

最后我们可以在templates.global.php中注册我们的 View Helper

'view_helpers' => [
    'factories' => [
        # use factory to grab an instance of CurrentUrlHelper
        'currentRoute' => CurrentUrlHelperFactory::class 
    ]
],
Run Code Online (Sandbox Code Playgroud)
  • 在 ROUTING_MIDDLEWARE 之后和 DISPATCH_MIDDLEWARE 之前注册我们的中间件非常重要!

  • 另外,我们只有 CurrentUrlHelperFactory 才能将其分配给键“currentRoute”。

现在您可以在任何模板文件中使用助手:)

<?php // in layout.phtml file
  $index_css   = $this->currentRoute('home-page') ? 'active' : 'none'; 
  $about_css   = $this->currentRoute('about') ? 'active' : 'none'; 
  $contact_css = $this->currentRoute('contact') ? 'active' : 'none';  
?>
Run Code Online (Sandbox Code Playgroud)