4

PSR-7 is going to be standardized soon (I believe). That's got me thinking about middlewares, such as used by Phly, StackPHP, and ConnectJS.

The way ConnectJS works is that it modifies the request object when a middleware needs to add something. For example, cookie-session creates a session property on the req object:

app.use(session({
  keys: ['key1', 'key2']
}))

app.use(function (req, res, next) {
  var n = req.session.views || 0 // <-- req.session is managed by the session middleware
  req.session.views = ++n 
  res.end(n + ' views')
})

With PSR-7, both our Request and Response objects are (supposed to be) immutable, so how are we supposed to pass along additional data like this? i.e. where would be the best place to store a 'session' object or a 'user' object created by an authentication middleware?

mpen
  • 237,624
  • 230
  • 766
  • 1,119
  • I don't know very well middlewares and ConnectJs, but I think that you can solve your immutability problem by creating a new instance of a Request or Response, instead of mutating it, and returning the new instance. Maybe this could help: https://github.com/phly/conduit#next – marcosh Mar 09 '15 at 22:53
  • @marcosh Right, but under which property defined by the interface would you store such data? – mpen Mar 09 '15 at 23:01
  • As long as the property you need to add does not have a counterpart in the HTTP message, I would not use a property defined by the interface, but I would use a newly defined property, like $request->session – marcosh Mar 10 '15 at 07:28
  • @marcosh Then all your typehinting goes out the window :\ – mpen Mar 10 '15 at 15:33
  • I'm not sure I understand fully your observation. If you define a new property $request->session, then the class of $request does not vary and it's still an instance of RequestInterface – marcosh Mar 10 '15 at 15:59
  • @marcosh Yes, if I type-hint against `RequestInterface`, then `$request->session` will be flagged as an error by my IDE. I can't type-hint against a more specific class either; what if one middleware adds `->session` and another adds `->user`? – mpen Mar 10 '15 at 16:25
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/72689/discussion-between-marcosh-and-mark). – marcosh Mar 10 '15 at 16:38
  • but actually my approach defeats the purpose of having immutable objects, so I recognize it's not the correct one. Looking better in the documentation of the ServerRequestInterface I saw that you can use attributes to store values that are computed from the current request. Maybe this is a better approach – marcosh Mar 10 '15 at 16:51

2 Answers2

3

Request and Response objects in PSR-7 are implemented as value objects, hence they are immutable.

Every time you need a different object, you create a new instance from the previous one, like

$newRequest = $oldRequest->withMethod('GET');

and from that point on use the new instance.

In middlewares you would have to pass the new instance to the next() function that calls the next middleware (see here for example).

If you need to store in the request object additional data computed from your current request, in the ServerRequestInterface there are defined the withAttribute and the withAttributes methods that allow you to do exactly that.

A common use case for this is for storing the results of routing, but you can surely use them to store other additional data of the request, like session or user data

marcosh
  • 8,079
  • 2
  • 41
  • 64
-1

Do not store at all. Inject it as parameter into consumer function. For instance:

function doSomething(reqest, response, session, user, foo, bar, ...)

Be explicit.

kenorb
  • 118,428
  • 63
  • 588
  • 624
  • It doesn't work like that. The "action" method that you're talking about and the middleware I'm talking about might be separated by 20 other middlewares. It needs to be passed along. – mpen May 30 '15 at 21:53