Is it bad practice to use the request object from the container?

I have middleware:

$middleWare = function ($request, $response, $next) {
    $request = $request->withAttribute('foo', 'bar');
    $response =  $next($request, $response);
    return $response;
};

Then my controller method to output foo, getting request from the container:

public function showFoo(){
    $foo = $this->container->get('request')->getAttribute('foo');
}

$foo = null

But using the $request:

public function showFoo(Request $request, Response $response){
    $foo = $request->getAttribute('foo');
}

$foo = bar

Obviously the container is not updated and uses the original request data whereas the passed-in request is from the middleware chain and contains the updated attribute

So, generally speaking, is it bad practice to rely on the container request (and response) object?

I’m just starting with Slim. I assume it’s possible to write apps that don’t rely on the container’s request/response objects but it seems like a bit of a gotcha.

I understand it’s to be removed in Slim 4. When is that to be released?

The request object is looped through the whole middleware queue and manipulated if necessary. The content (the attributes) can vary depending on when you get the request object. The middleware stack is run through in a certain order (in Slim it goes from bottom to top) and is handed over to the controller action at the end. The “finished” request object will be handed over in your action at the end. So if you want to be sure, use the Request object in your action e.g.

public function showFoo(Request $request, Response $response){
    $foo = $request->getAttribute('foo');
}

I understand it’s to be removed in Slim 4.

What do you mean exaclty?

I don’t think that isn’t quite right. Middleware is called both before being passed to $app (and your controller) and after leaving the controller before the response is sent back to the client.

<?php
/**
 * Example middleware closure
 *
 * @param  \Psr\Http\Message\ServerRequestInterface $request  PSR7 request
 * @param  \Psr\Http\Message\ResponseInterface      $response PSR7 response
 * @param  callable                                 $next     Next middleware
 *
 * @return \Psr\Http\Message\ResponseInterface
 */
function ($request, $response, $next) {
    $response->getBody()->write('BEFORE'); // Your controller action has not run, this will be available to the controller
    $response = $next($request, $response); // Pass along to any remaining middleware, towards the app
    $response->getBody()->write('AFTER'); // Your controller action has run, you can still make modifications as the response hasn't yet been sent.
    return $response;
};

I believe Slim’s Request and Response objects will be removed from the container, and Slim will not ship with a default container. You will be free to add your own container. Is this what you are referring to? Slim 4 will not likely reach beta for another few months.

What would be considered bad practice in your example isn’t getting the request from the container (that’s the right place to find it) but rather to not pass the container to your controller class. Instead of passing the container to your controller class, pass it just what it needs.

See some examples and discussion on that here:
https://akrabat.com/di-factories-for-slim-controllers/

Thanks for your reply.

In my example above I didn’t show the code that passes the container into the constructor, so the container has been passed in, thus:

Class DbController{
    
    protected $container;
    
    public function __construct(ContainerInterface $container){
        $this->container = $container;
    }

    public function showFoo(){
        $foo = $this->container->get('request')->getAttribute('foo');
    }
   
}

I’m confused by what you’re saying. I’ve passed the container in during container setup:

$container['DbController'] = function ($c) {
    return new App\Controllers\DbController($c);
};

And this is the call that adds the route and middleware:

$app->get('/', 'DbController:showFoo')->add($middleWare);

I understand Slim passes the request object into my showFoo method, but I’m confused as to why the container’s request is out of sync with it since I’m assuming the DbController class won’t be instantiated until after the middleware has run and therefore the container passed in to the contructor should have the same request data.

But I must have that wrong as per my OP. Could you clarify. Thanks.

But on the way out, can I alter the request in the middleware? Surely it only make sense to modify the response on the way out since at that point the app has already processed the request data handed to it by the middlewares?

The Request and Response objects are immutable. You can alter the request on the way out, although there wouldn’t be as many use cases for it.

I got that from a comment of yours elsewhere here, and from these discussions:

Yes, I misspoke. I meant “work with” or use the request on the way out. I appreciate the request and response are immutable.

Right. So, the answer to my original question is: the request and response in the container should not be used since the state of the request or response may have been “altered” by middlewares.

It makes sense that removing those from the container is being considered.