-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
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
Add support for PSR-15 middlewares #2379
Conversation
Thanks :) I will take a good look at this today or tomorrow, I know akrabat is at a conference this week so he might be able to get around to it next. |
|
||
public function handle(ServerRequestInterface $request): ResponseInterface | ||
{ | ||
return call_user_func($this->next, $request, $this->response); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since $this->next
is `callable, and this PR requires PHP 7 and up, that means you can simplify the above to:
return ($this->next)($request, $this->response);
My understanding is that call_user_func
is slower than PHP's native dereferencing in PHP 7, so the above will also be more performant.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I used call_user_func
since that was used throughout the Slim codebase. I think those occurrences should be changed in one go. Will push a patch for that.
Slim/CallableResolver.php
Outdated
@@ -8,8 +8,10 @@ | |||
*/ | |||
namespace Slim; | |||
|
|||
use Interop\Http\Server\MiddlewareInterface; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a heads-up: PSR-15 passed today, though we're waiting to announce it until the packages are on Packagist — though that should be within the next few hours after I write this. As such, you'll be able to require psr/http-server-middleware
instead of http-interop/http-server-middleware
, and the above will become Psr\Http\Server\MiddlewareInterface
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I pushed a patch for the switch to psr/http-server-middleware
.
* and is used only inside of the Slim application; it is not visible | ||
* to—and should not be used by—end users. | ||
*/ | ||
final class SinglePassMiddleware implements RequestHandlerInterface |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of SinglePassMiddleware
, may I suggest StandardsBasedMiddleware
or PsrMiddleware
here?
I've noted in communicating with ZF folks that many are not clear what is meant by "single-pass" and "double-pass", despite us having documented it. Having a name that indicates the type of middleware in terms of where you might find a definition helps.
Also, I'd add an @see
annotation with a link to the accepted standard (we'll have that on the fig-standards repo shortly).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, I personally prefer a name that describes the functionality. With PsrMiddleware
it's not that clear whether the middleware is implementing PSR 15 or (as in our case) adapts a PSR-15 middleware.
Anyway, I've no strong objections against PsrMiddleware
so i'll push a patch that renames that one (consistent naming across frameworks is probably not that bad).
@@ -87,13 +87,13 @@ public function getCallableResolver() | |||
/** | |||
* Prepend middleware to the middleware collection | |||
* | |||
* @param callable|string $callable The callback routine | |||
* @param MiddlewareInterface|callable|string $middleware The middleware routine |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have you imported this interface within this class file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I missed that one, will fix.
.travis.yml
Outdated
env: COMPOSER_ARGS='--prefer-lowest' | ||
- php: nightly | ||
allow_failures: | ||
- php: hhvm |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's just take hhvm out - we're not supporting it in 4.x
I've been thinking about this a bit. While I appreciate that it's easier to keep the internals the same as Slim 3, I'd like to explore if we can make PSR-15 the default internally and "wrap" the current signatures. Going forward, this makes more sense to me as we probably won't support the current signatures in Slim 5. Thoughts? |
@bnf are you moving forward with this PR? I'm curious as I will tackle it after my next couple of PRs if you aren't. |
Hi @akrabat, hi @l0gicgate, Sorry, I missed your comments/thoughts. Therefore now my (very late) reaction: I still think this is the right approach and actually considered it ready. Therefore I didn't do more work on this, because I was waiting for it to be merged. It's actually used in production as a backport for slim v3: https://packagist.org/packages/bnf/slim3-psr15
Going with a pure PSR-15 solution and adding a wrapper for double pass middlewares (as in #2555) results in (hard to detect) breaking behaviour, as the wrapper has to create a new
Existing middleware code that expect to be able to pass a modified Thanks, Benjamin |
Use the `$callable()` syntax instead. See https://trowski.com/2015/06/20/php-callable-paradox/
…s other than handle() If 'FooBar:customMethod' is specified to be dispatched, the CallableResolver must not resolve to the handle() method even though FooBar implements the RequestHandlerInterface. It should only do that, if no method name is given.
… grasp Do not invoke objects that don't need them, rather use early retuns. No need to check is_callable for Closures or classes that implement RequestHandlerInterface where instanceof is sufficient to return early.
PSR-15 middlewares can be registered using the existing API: `App::add()` and `Routable::add()` Those methods are extended to accept objects that implement the MiddlewareInterface (or class names that refer to classes which implement the MiddlewareInterface). We do not add new entry points for middleware registration, as the type of the middleware can be detecting through the MiddlewareInterface which all PSR-15 middlewares implement. Both, classes that do not implement MiddlewareInterface, and closures will be handled as single pass middleware – as before. That means there's no support for closures with a PSR-15 style single-pass signature. The detection of the middleware type is implemented in the callable resolver. While that might look like something which is out of scope for the CallableResolver, reasons are: a) The internal slim middleware stack stays at is – it handles callables only. (and in cannot be changed anyway as long double-pass middlewares need to be supported. Double-pass middlewares expect a Response object that needs to be passed along the middleware stack. Therefore we'd need to wrap PSR-15 middleware's in any case – which is what this change provides) b) the CallableResolver resolves (in terms for transforms) a callable from PSR-15 style middleware. TODO: Add more tests for: - Adapter\PsrMiddleware - Routable with PSR-15 Middlewares Resolves slimphp#2050
To this point, we only need one PR to get PSR-15 support into Slim 4. However, the BC problems that @bnf highlights (and @l0gicgate also highlighted in Slack at some point in the past to me) do need to be explicitly discussed I think. My initial reaction as @l0gicgate noted is that passing the response down the chain is bad, so my natural reaction is that I don't mind breaking it in Slim 4. However, is that the right call? I could definitely be wrong. |
PSR-15 middlewares can be registered using the existing API:
App::add()
andRoutable::add()
Those methods are extended to accept objects that implement
the MiddlewareInterface (or class names that refer to classes
which implement the MiddlewareInterface).
We do not add new entry points for middleware registration, as the type
of the middleware can be detecting through the MiddlewareInterface
which all PSR-15 middlewares implement.
Both, classes that do not implement MiddlewareInterface, and closures will
be handled as single pass middleware – as before.
That means there's no support for closures with a PSR-15 single-pass
signature.
The detection of the middleware type is implemented
in the callable resolver. While that might look like
something which is out of scope for the CallableResolver, reasons are:
(and in cannot be changed anyway as long double-pass middlewares
need to be supported. Double-pass middlewares expect a Response object
that needs to be passed along the middleware stack. Therefore we'd need to
wrap PSR-15 middleware's in any case – which is what this change provides)
from PSR-15 style middleware.
TODO: Add more tests for:
Resolves #2050