Slim4: how to get args for is_current_url() in twig

Good day. The code:
router:

$app->get('/user/view/{id}', UserView::class)->setName('user.view');

twig:

<li class="{{ is_current_url('user.view') ? 'active' : '' }}">

The problem for is_current_url is in missing parameter id . In this case we get Missing data for URL segment: id error. How can i check if rule user.view is current url? I try do it with middleware:

public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface {
		$routeContext = RouteContext::fromRequest($request);

		if (($route = $routeContext->getRoute()) === NULL) {
			return $handler->handle($request);
		}

		$args = $route->getArguments();
		$this->twig->getEnvironment()->addGlobal('uri_args', $args);

		return $handler->handle($request);
	}

twig:

<li class="{{ is_current_url('user.view', uri_args) ? 'active' : '' }}">

All work fine, but only on /user/view/{id} route. On all other routes i get error Missing data for URL segment: id, because the uri_args array is empty. How can i resolve this problem?

You need to pass in the data parameters to is_current_url . Example if the url is /user/view/1 you’d need to do is_current_url('user.view', ['id' => 1]) which would return true.

Yes, i understand this. But I can’t figure out what code to write in the template. Now it look like this:
router:

$app->get('/', RootPage::class)->setName('root.page');
$app->get('/user/add', UserAdd::class)->setName('user.add');
$app->get('/user/view/{id}', UserView::class)->setName('user.view');

twig:

<li class="{{ is_current_url('root.page') ? 'active' : '' }}">
<li class="{{ is_current_url('user.add') ? 'active' : '' }}">
<li class="{{ is_current_url('user.view', uri_args) ? 'active' : '' }}">

The code above throw exception Missing data for URL segment: id on all pages except user.view because on those pages uri_args are empty.

In your example you are mixing the global variable name uri_args and args.

But the main “problem” is that $route->getArguments(); only returns the route arguments for the current route and not for all other routes. Even if you fix the variable name, you still would get an error like Missing data for URL segment "id". So is_current_url('user.view', args) will only work if you enter the url for the user.view route with an id like /user/view/1234 into the browser.

Sorry, args must be uri_args of course. No args var in my code, only uri_args. I edited my previous posts to be correct.

The main question, how can i check if route like /user/view/{id} is current or not? We consider that these routes can be many: /set-lang/{locale}, /post/{slug} etc. The only way that I see now is to write some kind of handler over is_current_url, but it does not look like a good solution

I’m sure this problem has already been solved by someone.

This is “very easy” by setting the current route name as global variable. Then you can compare the route name in your twig templates.

The middleware:

<?php

namespace App\Middleware;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Slim\Routing\RouteContext;
use Slim\Views\Twig;

final class RouteNameMiddleware implements MiddlewareInterface
{
    /**
     * @var Twig
     */
    private $twig;

    public function __construct(Twig $twig)
    {
        $this->twig = $twig;
    }

    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        $routeContext = RouteContext::fromRequest($request);
        $route = $routeContext->getRoute();

        if ($route === null) {
            return $handler->handle($request);
        }

        $this->twig->getEnvironment()->addGlobal('route_name', $route->getName());

        return $handler->handle($request);
    }
}

Twig usage:

<li class="{{ route_name == 'root.page' ? 'active' : '' }}">
<li class="{{ route_name == 'user.add' ? 'active' : '' }}">
<li class="{{ route_name == 'user.view' ? 'active' : '' }}">
1 Like

Great, thank you! I had to guess myself.
A little tip for reading this thread. If you have several routes at one menu you can use in twig operator:

<li class="{{ route_name in ['user.add', 'user.view', 'user.delete'] ? 'active' : '' }}">

instead of

<li class="{{ (route_name == 'user.add' or route_name == 'user.view' or route_name == 'user.delete'] ? 'active' : '' }}">
1 Like