1

我知道我可以生成URL传递路线名称如何查看获得与之匹配的路由名称 - Zend的表现

<?php echo $this->url('route-name') #in view file ?> 

但我可以在相反方向的信息? 从当前的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'; 
?> 

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

+0

你可能需要一个助手来获取路由器,它有一个'match'方法。 [未经测试的声称实现](http://stackoverflow.com/a/36337414/2908724)。 – bishop

回答

3

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

我们知道我们可以得到RouteResult,但是来自中间件__invoke()方法中的Request对象。

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

由于@timdev建议,我们将在现有的帮手UrlHelper找到灵感,并在自定义视图助手让几乎相同implementation

总之我们将创建2个类。

  1. CurrentUrlHelper与方法setRouteResult()
  2. CurrentUrlMiddleware__invoke($ REQ,$资源,$ NEXT)

我们将在CurrentUrlMiddleware注入CurrentUrlHelper和 在__invoke()方法中调用CurrentUrlHelper :: setRouteResult()与适当的RouteResult实例。 稍后我们可以使用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 
    } 
} 

而我们的新助手:

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); 
    } 
} 

现在,我们只需要注册一个新的视图助手和中间件在configs:

dependencies.global.php

'dependencies' => [ 
    'invokables' => [ 
     # dont have any constructor! 
     CurrentUrlHelper::class => CurrentUrlHelper::class, 
    ], 
] 

middleware-pipeline.globa l.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, 
], 

而且finaly我们可以templates.global注册我们的视图助手。PHP

'view_helpers' => [ 
    'factories' => [ 
     # use factory to grab an instance of CurrentUrlHelper 
     'currentRoute' => CurrentUrlHelperFactory::class 
    ] 
], 
  • 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'; 
?> 
+0

确定您可以使用反射,但该方法受到保护是有原因的。这个技巧将来可能不再适用。 – xtreamwayz

+1

是的,反思很快,但不是很好的决定。我改变它。 – tasmaniski

+0

$ routeResult = $ request-> getAttribute('Zend \ Expressive \ Router \ RouteResult'); $ routeName = $ routeResult-> getMatchedRouteName(); 我认为这会更好地将其替换为: $ router = $ container-> get(RouterInterface :: class); $ router-> match($ request) - > getMatchedRouteName(); – Andriy

0

,正如你在自我回答说明,UrlHelper是注意一个有用的东西。但是,创建一个依赖于UrlHelper(和反射)的新帮手并不理想。

你最好写自己的帮手,启发UrlHelper但不依赖于它。

您可以查看UrlHelper,UrlHelperFactory和UrlHelperMiddleware的代码来通知您自己的实现。

+0

谢谢!我真的在现有的UrlHelper中找到了很好的灵感:) – tasmaniski

0

您可以将模板渲染器包装到另一个类中,并将请求传递到那里,减去您需要的内容并将其注入到真实模板渲染器中。

行动中间件:

class Dashboard implements MiddlewareInterface 
{ 
    private $responseRenderer; 

    public function __construct(ResponseRenderer $responseRenderer) 
    { 
     $this->responseRenderer = $responseRenderer; 
    } 

    public function __invoke(Request $request, Response $response, callable $out = null) : Response 
    { 
     return $this->responseRenderer->render($request, $response, 'common::dashboard'); 
    } 
} 

新的包装类:

<?php 

declare(strict_types = 1); 

namespace Infrastructure\View; 

use Psr\Http\Message\ResponseInterface as Response; 
use Psr\Http\Message\ServerRequestInterface as Request; 
use Zend\Diactoros\Stream; 
use Zend\Expressive\Router\RouteResult; 
use Zend\Expressive\Template\TemplateRendererInterface; 

class ResponseRenderer 
{ 
    private $templateRenderer; 

    public function __construct(TemplateRendererInterface $templateRenderer) 
    { 
     $this->templateRenderer = $templateRenderer; 
    } 

    public function render(Request $request, Response $response, string $templateName, array $data = []) : Response 
    { 
     $routeResult  = $request->getAttribute(RouteResult::class); 
     $data['routeName'] = $routeResult->getMatchedRouteName(); 

     $body = new Stream('php://temp', 'wb+'); 
     $body->write($this->templateRenderer->render($templateName, $data)); 
     $body->rewind(); 

     return $response->withBody($body); 
    } 
} 

代码是从GitHub借来的。