Pragmatism in the real world

Redirecting in Slim 2 Middleware

I recently ran into a problem with calling redirect() in a Slim Framework 2 middleware class, so I thought I’d better document the solution so that I remember in future!

The authentication middleware looks roughly like this:

class Authentication extends \Slim\Middleware
{
    public function call()
    {
        if (!$this->isLoggedIn()) {
            $app = \Slim\Slim::getInstance();
            $app->redirect($app->urlFor('login'));
        }

        $this->next->call();
    }

    // other methods...
}

The problem is that you can’t call $app->redirect() in Middleware as redirect() is designed to only run in application route callbacks and Middleware should only act on the request and response objects.

This is because the app’s redirect() method calls through to stop() which throws a Stop exception which is intended to be caught by the app’s call() method. However, if this exception is thrown in middleware, then it isn’t caught by call() and the redirect doesn’t work. What’s weird is that it works on some (most?) web servers but not all.

The correct way to redirect in middleware, use the Response‘s redirect() method instead like this:

class Authentication extends \Slim\Middleware
{
    public function call()
    {
        if (!$this->isLoggedIn()) {
            $app = \Slim\Slim::getInstance();
            return $app->response()->redirect($app->urlFor('login'));
        }

        $this->next->call();
    }

    // other methods...
}

Note that we return the result of $response->redirect() so that the next item in the chain isn’t called.