如何在View中获得匹配的路由名称 - Zend Expressive

时间:2016-06-28 14:19:39

标签: php zend-framework zend-framework3 zend-expressive fastroute

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

<?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文件中。

3 个答案:

答案 0 :(得分:4)

根据我的研究,公共方法 getMatchedRouteName()中的RouteResult实例中有此类信息。问题是如何从View访问此实例。

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

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

正如@timdev建议的那样,我们会在现有助手UrlHelper中找到灵感,并在自定义View Helper中创建几乎相同的implementation

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

  1. CurrentUrlHelper ,方法为 setRouteResult()
  2. CurrentUrlMiddleware __ invoke($ req,$ res,$ next)
  3. 我们将在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
        }
    }
    

    我们的新助手:

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

    现在我们只需要在配置中注册新的View Helper和Middleware:

    <强> dependencies.global.php

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

    <强>中间件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,
    ],
    

    最后我们可以在 templates.global.php

    中注册我们的View Helper
    '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';  
    ?>
    

答案 1 :(得分:0)

正如您在自我回答中所述,UrlHelper值得关注。但是,创建一个依赖于UrlHelper(和反射)的新助手并不理想。

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

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

答案 2 :(得分: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