Я знаю, что могу генерировать 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.
Из моего исследования, есть такая информация в RouteResult экземпляр в публичном методе getMatchedRouteName (). Проблема в том, как добраться до этого экземпляра из View.
Мы знаем, что мы можем получить RouteResult, но из объекта Request, который находится в методе Middleware __invoke ().
public function __invoke($request, $response, $next){
# instance of RouteResult
$routeResult = $request->getAttribute('Zend\Expressive\Router\RouteResult');
$routeName = $routeResult->getMatchedRouteName();
// ...
}
Как рекомендовал @timdev, мы найдем вдохновение в существующем помощнике UrlHelper и сделать почти то же самое реализация в кастомном View Helper.
Короче мы создадим 2 класса.
Мы вставим CurrentUrlHelper в CurrentUrlMiddleware и
в __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);
}
}
Теперь нам нужно только зарегистрировать наш новый 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,
],
И наконец мы можем зарегистрировать наш View Helper в 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';
?>
Как вы отмечаете в своем ответе, UrlHelper — полезная вещь для заметки. Однако создание нового помощника, который зависит от UrlHelper (и отражения), не является идеальным.
Вам лучше написать свой собственный помощник, вдохновленный UrlHelper, но не зависимый от него.
Вы можете посмотреть на код для UrlHelper, UrlHelperFactory и UrlHelperMiddleware, чтобы проинформировать свою собственную реализацию.
Вы можете обернуть рендерер шаблонов в другой класс и передать туда запрос, вычесть то, что вам нужно, и вставить его в реальный рендерер шаблонов.
Промежуточное программное обеспечение действий:
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.