Search code examples
phpslimhttp-redirectforward

How to forward an HTTP request with Slim Framework


Is it possible to forward a request in Slim? The meaning of "forward", like in JavaEE, is to internally redirect to another route without return the response to the client and maintaining the model.

For example:

$app->get('/logout',function () use ($app) {
   //logout code
   $app->view->set("logout",true);
   $app->forward('login'); //no redirect to client please
})->name("logout");

$app->get('/login',function () use ($app) {
   $app->render('login.html');
})->name("login");

Solution

  • In my opinion, the best way to do this would be by using Slim's internal router (Slim\Router) capabilities and dispatching (Slim\Route::dispatch()) the matched route (meaning: executing the callable from a matched route without any redirect). There are a couple of options that come to mind (depending on your setup):

    1. calling a named route + callable doesn't take any arguments (your example)

    $app->get('/logout',function () use ($app) {
       $app->view->set("logout",true);
    
       // here comes the magic:
       // getting the named route
       $route = $app->router()->getNamedRoute('login');
    
       // dispatching the matched route
       $route->dispatch(); 
    
    })->name("logout");
    

    This should definitely do the trick for you, but I still want to show the other scenarios ...


    2. calling a named route + callable with arguments

    The above example will fail ... because now we need to pass arguments to the callable

       // getting the named route
       $route = $app->router()->getNamedRoute('another_route');
    
       // calling the function with an argument or array of arguments
       call_user_func($route->getCallable(), 'argument');
    

    Dispatching the route (with $route->dispatch()) will invoke all middleware, but here we are just calling the the callable directly ... so to get the full package we should consider the next option ...


    3. calling any route

    Without named routes we can get a route by finding the one matching the a http method and pattern. For this we use Router::getMatchedRoutes($httpMethod, $pattern, $reload) with reload set to TRUE.

       // getting the matched route
       $matched = $app->router()->getMatchedRoutes('GET','/classes/name', true);
    
       // dispatching the (first) matched route
       $matched[0]->dispatch(); 
    

    Here you might want to add some checks and for example dispatch notFound in case no route is matched. I hope you get the idea =)