Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Slim 3.0 Getting Route Params in Middleware #1505

Closed
bradynpoulsen opened this issue Sep 21, 2015 · 15 comments

Comments

@bradynpoulsen
Copy link

commented Sep 21, 2015

I am creating a controller class and trying to add a method on my controller to load a object based on its route ID. I've got that all written and ready to work EXCEPT I don't know how to grab the route parameters from the request. There's also no documented way for middleware to access those parameters.

$app->group('/users', function () {
    $controller = new MyController();
    $this->get('/', [$controller, 'index']);
    $this->get('/{id}', [$controller, 'show'])->add($controller);
});
class MyController
{
    // Fulfills invoke status for Middleware, see http://www.slimframework.com/docs/concepts/middleware.html#invokable-class-middleware-example
    public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next)
    {
        // how do I get $routeParams???
        $userId = $routeParams['id'];
        $user = $userMapper->findById($userId);
        if ($user) {
           $request = $request->withAttribute('user', $user);
           return $next($request, $response);
        } else {
            // setup $response to contain a 404 response, don't call $next
            return $response;
        }
    }

    public function show(ServerRequestInterface $request, ResponseInterface $response, array $args)
    {
        $user = $request->getAttribute('user');  // already loaded by middleware
        return $response->getBody()->write(json_encode($user)); // varies, but for example
    }
@bradynpoulsen

This comment has been minimized.

Copy link
Author

commented Sep 21, 2015

I think I've figured out a solution to my problem; however, I still would like to know how a middleware would access router parameters or what people think on that being poor middleware design

For now I'm just doing the __call() magic method on my controller and making my show action private. Something like:

$app->group('/users', function () {
    $controller = new MyController();
    $this->get('/', [$controller, 'index']);
    $this->get('/{id}', [$controller, 'show']);
});
class MyController
{
    public function __call($name, array $arguments)
    {
        list($request, $response, $args) = $arguments;
        $user = $userMapper->findById($args['id']);
        if ($user) {
            $request = $request->withAttribute('user', $user);
            return call_user_func([$this, $name], $request, $response, $args);
        } else {
            // $response now contains 404 response, don't call method
            return $response;
        }
    }

    private function show(ServerRequestInterface $request, ResponseInterface $response, array $args)
    {
        $user = $request->getAttribute('user');  // already loaded by middleware
        return $response->getBody()->write(json_encode($user)); // varies, but for example
    }
}
@akrabat

This comment has been minimized.

Copy link
Member

commented Sep 22, 2015

You'll find the route parameters in the third element of the 'routeInfo' attribute. We'd love a PR documenting this :)

$routeParams = $request->getAttribute('routeInfo')[2];

@akrabat akrabat closed this Sep 22, 2015

@akrabat akrabat added the Slim 3 label Sep 22, 2015

@bradynpoulsen

This comment has been minimized.

Copy link
Author

commented Oct 3, 2015

As a side note, this option does not work for application middleware

@kevinmlong

This comment has been minimized.

Copy link

commented Nov 18, 2015

Agree with @bradynpoulsen that it doesn't work for middleware. Would also be able to access route arguments from within middleware

@akrabat

This comment has been minimized.

Copy link
Member

commented Nov 18, 2015

By default, the route hasn't been worked out when app middleware is running, which is why it's not working for you.

If you need this, then you can enable this setting:

$settings = [
    'settings' => [
        'determineRouteBeforeAppMiddleware' => true,
    ],
];
$app = new Slim\App($settings);
@kevinmlong

This comment has been minimized.

Copy link

commented Nov 18, 2015

@akrabat - this does solve the problem. Thanks!

@akrabat

This comment has been minimized.

Copy link
Member

commented Nov 18, 2015

This works @kevinmlong:

$settings = [
    'settings' => [
        'determineRouteBeforeAppMiddleware' => true,
    ],
];
$app = new \Slim\App($settings);

$app->get("/{name}", function ($request, $response, $args) {
    return $response->write("Hello {$args['name']}");
});

$app->add(function ($request, $response, $next) {
    var_dump($request->getAttribute('routeInfo')[2]);

    return $next($request, $response);
});

Navigating to http://develop-testbed.slim3.dev/rob gives me:

/www/dev/slim3/develop-testbed/public/index-scratch.php:23:
array (size=1)
  'name' => string 'rob' (length=3)
Hello rob
@kevinmlong

This comment has been minimized.

Copy link

commented Nov 18, 2015

@akrabat - I sent the other comment to quickly. I suppose I deleted it after you saw it. Thanks!

A related issue ....

In my middleware, I am calling

$next($request,$response);
-- doing stuff --

As it goes through the routing methods, it returns a response. In some cases it changes the status to a different code (e.g. 400) like below:

$newResponse = $this->response->withStatus(404)
                                     ->withHeader('Content-Type', 'application/json')
                                     ->write(...stuff...);
return $newResponse;

when the application returns to the middleware, the response object has a code of 200. When returned, it has the right body, but the wrong status. Thoughts?

@silentworks

This comment has been minimized.

Copy link
Member

commented Nov 18, 2015

@kevinmlong $this->response is probably stale. Where is that coming from?

@kevinmlong

This comment has been minimized.

Copy link

commented Nov 18, 2015

It's in the route method

$app->get('path to route', function ($request, $response, $args) {
    do some stuff
    $newResponse = $this->response->withStatus(404)
                                     ->withHeader('Content-Type', 'application/json')
                                     ->write(...stuff...);
return $newResponse;
}

The code then returns to the middleware. The code response here is 200 instead of 404. If I return the response, I get the right body from the write(..stuff..) but the code is not 404.

@silentworks

This comment has been minimized.

Copy link
Member

commented Nov 18, 2015

@kevinmlong you need to use $response instead of $this->response. $this->response is a stale response object while $response is the current one from this request. You can even do exactly what @akrabat did in his example.

$app->get('path to route', function ($request, $response, $args) {
    return $response->withStatus(404)
                   ->withHeader('Content-Type', 'application/json')
                   ->write(...stuff...);
});
@kevinmlong

This comment has been minimized.

Copy link

commented Nov 18, 2015

@silentworks - that doesn't work. it still returns to the middleware with a 200 code.

@kevinmlong

This comment has been minimized.

Copy link

commented Nov 18, 2015

@silentworks - the response object is getting updated, since the body is being updated correctly.

@kevinmlong

This comment has been minimized.

Copy link

commented Nov 18, 2015

@silentworks - I figured it out. Need to change the middleware to:

public function __invoke($request, $response, $next){
// do some stuff
$newResponse = $next($request,$response);
// do more stuff
return $newResponse;
}
@HarshVarshney

This comment has been minimized.

Copy link

commented Sep 26, 2016

Add following line in configuration
$config['determineRouteBeforeAppMiddleware'] = true;

In middleware
$route = $request->getAttribute('route');
$arguments = $route->getArguments();
print_r($arguments);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
5 participants
You can’t perform that action at this time.