Search code examples
slimslim-4

How to set an attribute to route definition in Slim4 and use it in a middleware


I need to set a custom attribute in the route definition and use it a route middleware. For example, I need to manage the refer page to redirect the user after the login.

This is my routes definition:

return function (App $app) {
    $app->get('/', Home::class. ':home')->setName('home');
    $app->get('/login', UserAction::class. ':getLogin')->setName('login')->setAttribute('norefer',true);
    $app->post('/login', UserAction::class. ':postLogin');
};

The ->setAttribute('norefer',true); is what I'm looking for and seems it doesn't exist.

I need this attribute using ->getAttribute("norefer") in a middleware so I can store the last referable page visited by the user:

public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
    $routeContext = RouteContext::fromRequest($request);
    $route = $routeContext->getRoute();
    if (!empty($route) && !$routeContext->getRoute()->getAttribute("norefer")) {
        $referName = $routeContext->getRoute()->getName();
        $referArgs = $routeContext->getRoute()->getArguments();
        $this->session->set("referName", $referName);
        $this->session->set("referArgs", $referArgs);
    }
    return $handler->handle($request);
}

So, in the session I can store the last referable page and use it after the login process to redirect the user to his page.


Solution

  • You could add a NoRefererMiddleware to routes you want to exclude from the redirection logic. NoRefererMiddleware just sets a noreferer attribute to the request object if its called.

    <?php
    
    use App\Middleware\NoRefererMiddleware;
    use Slim\App;
    
    return function (App $app) {
        $app->get('/', Home::class. ':home')->setName('home');
        $app->get('/login', UserAction::class. ':getLogin')->setName('login')->add(NoRefererMiddleware::class);
        $app->post('/login', UserAction::class. ':postLogin');
    };
    

    File: src/Middleware/NoRefererMiddleware.php

    <?php
    
    namespace App\Middleware;
    
    use Psr\Http\Message\ResponseInterface;
    use Psr\Http\Message\ServerRequestInterface;
    use Psr\Http\Server\MiddlewareInterface;
    use Psr\Http\Server\RequestHandlerInterface;
    
    final class NoRefererMiddleware implements MiddlewareInterface
    {
        public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
        {
            $request = $request->withAttribute('noreferer', true);
    
            return $handler->handle($request);
        }
    }
    

    Usage

    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        $noReferer = $request->getAttribute('noreferer');
    
        if ($noReferer !== true) {
            $routeContext = RouteContext::fromRequest($request);
            $route = $routeContext->getRoute();
            if ($route !== null) {
                $referName = $routeContext->getRoute()->getName();
                $referArgs = $routeContext->getRoute()->getArguments();
                $this->session->set('referName', $referName);
                $this->session->set('referArgs', $referArgs);
            }
        }
    
        return $handler->handle($request);
    }