Access Database in a Middleware

Hello,

I wonder about my way of doing things.

I want to add a restriction to my route via a middleware.

If ok the road continues otherwise a redirection is made.

To do this, I need to recover a line in a database directly in my middleware.

I do so

    public function __invoke(Request $request, Handle $handler): Request|ResponseInterface
    {
        $routeContext = RouteContext::fromRequest($request);
        $route = $routeContext->getRoute();
        $db = $this->container->get('db');
        $i = $db->from('interventions')
            ->select('id, state')
            ->where('interventions.id = ?', [$route->getArgument('id')])
            ->fetch()
            ;
        if($i['state'] === 'BROUILLON'){
            $response = new Response();
            return $response->withHeader('Location', '/')->withStatus(302);
        }
        return $handler->handle($request);
    }

Is it correct to do so in a middleware or another solution would be possible?

Thanks.

(Sorry for my English)

A (PSR-15) middleware must always return a response object, so I would change the return type to ResponseInterface.

Also note that when you create a response object manually, the other middleware handler will not be called.

A real PSR-15 middleware implements the MiddlewareInterface. See here: PSR-15.

Hello Odan,

Thank you for your speed.

I modified my Middleware and implemented the MiddlewareInterface and thus fixed the return.

Is it possible to inject the Container in a constructor because I need to retrieve DB (if it’s not too dirty)?
(it works but I would like to be sure that I am on the right track)

Ex :

class IfNotValidedInterventionMiddleware implements MiddlewareInterface
{

    private Container $container;

    public function __construct(Container $container)
    {

        $this->container = $container;
    }

    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        $response = $handler->handle($request);
        $routeContext = RouteContext::fromRequest($request);
        $route = $routeContext->getRoute();
        $db = $this->container->get('db');
        $i = $db->from('interventions')
            ->select('id, state')
            ->where('interventions.id = ?', [$route->getArgument('id')])
            ->fetch()
        ;
        if($i['state'] === 'BROUILLON'){
            return $response->withHeader('Location', '/admin/interventions')->withStatus(302);
        }
        return $response;
    }
}

Thanks :slight_smile:

The DI container should never be used directly within your application. Instead I would recommend declaring the database class within the constructor to make it clear what dependencies are really needed.

Your latest middleware implementation uses the redirect on the outgoing direction, which means that the check and the redirect is too late. I would refactor the redirect to be handled for the ingoing direction.

Thank you for your feedback and your recommendations, I will correct all that.

1 Like