-
-
Notifications
You must be signed in to change notification settings - Fork 53
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
PSR-15 compatibility #253
PSR-15 compatibility #253
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -514,6 +514,42 @@ This is commonly used for cache handling and response body transformations (comp | |
> [Generator-based coroutines](../async/coroutines.md) anymore. | ||
> See [fibers](../async/fibers.md) for more details. | ||
|
||
## PSR-15 middleware | ||
|
||
Middleware handlers can also be classes implementing the `MiddlewareInterface` from the [PSR-15](https://www.php-fig.org/psr/psr-15/) recommendation: | ||
|
||
```php title="src/PsrMiddleware.php" | ||
<?php | ||
|
||
namespace Acme\Todo; | ||
|
||
use Psr\Http\Message\ResponseInterface; | ||
use Psr\Http\Message\ServerRequestInterface; | ||
use Psr\Http\Server\MiddlewareInterface; | ||
use Psr\Http\Server\RequestHandlerInterface; | ||
use React\Http\Message\Response; | ||
|
||
class PsrMiddleware implements MiddlewareInterface | ||
{ | ||
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface | ||
{ | ||
return Response::plaintext('Hello from PSR-15'); | ||
} | ||
} | ||
``` | ||
|
||
```php title="public/index.php" | ||
<?php | ||
|
||
use Acme\Todo\PsrMiddleware; | ||
|
||
// … | ||
|
||
$app->get('/user', new PsrMiddleware()); | ||
``` | ||
|
||
This is especially useful in order to integrate one of the many existing PSR-15 implementations as global middleware. | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I acknowledge that this is the bare minimum documentation, feel free to amend *g There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this is a solid start, let's focus on the API first and once we have a feeling what this should look like, we can adjust the documentation accordingly 👍 |
||
## Global middleware | ||
|
||
Additionally, you can also add middleware to the [`App`](app.md) object itself | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
<?php | ||
|
||
namespace FrameworkX\Io; | ||
|
||
use Psr\Http\Message\ResponseInterface; | ||
use Psr\Http\Message\ServerRequestInterface; | ||
use Psr\Http\Server\RequestHandlerInterface; | ||
use React\Http\Message\Response; | ||
use function React\Async\await; | ||
use function React\Promise\resolve; | ||
|
||
/** | ||
* @internal | ||
*/ | ||
class PsrAwaitRequestHandler implements RequestHandlerInterface | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is mostly "stolen" from https://github.com/friends-of-reactphp/http-middleware-psr15-adapter and that needs attribution – I'm not sure how you usually handle this? As comment in the class or README? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Normally we add a comment to the specific class, something like:
Nearly all of these projects are published under the MIT license, same goes for https://github.com/friends-of-reactphp/http-middleware-psr15-adapter |
||
{ | ||
|
||
/** | ||
* @var callable|null | ||
*/ | ||
private $next; | ||
|
||
public function __construct(callable $next = null) { | ||
$this->next = $next; | ||
} | ||
|
||
public function handle(ServerRequestInterface $request): ResponseInterface | ||
{ | ||
if ($this->next === null) { | ||
return new Response(); | ||
} | ||
Comment on lines
+29
to
+31
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a bit weird. But there are at least two occurrences of a handler invocation without the and this was the easiest solution I could think of to avoid these from exploding :) |
||
return await(resolve(($this->next)($request))); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
<?php | ||
|
||
namespace FrameworkX\Io; | ||
|
||
use Psr\Http\Message\ResponseInterface; | ||
use Psr\Http\Message\ServerRequestInterface; | ||
use Psr\Http\Server\MiddlewareInterface as PsrMiddlewareInterface; | ||
use React\Promise\PromiseInterface; | ||
use function React\Async\async; | ||
Check failure on line 9 in src/Io/PsrMiddlewareAdapter.php GitHub Actions / PHPStan (PHP 7.4)
Check failure on line 9 in src/Io/PsrMiddlewareAdapter.php GitHub Actions / PHPStan (PHP 7.3)
|
||
|
||
/** | ||
* @internal | ||
*/ | ||
class PsrMiddlewareAdapter | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should also be attributed to https://github.com/friends-of-reactphp/http-middleware-psr15-adapter There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as #253 (comment) |
||
{ | ||
|
||
/** | ||
* @var PsrMiddlewareInterface | ||
*/ | ||
private $middleware; | ||
|
||
public function __construct(PsrMiddlewareInterface $middleware) { | ||
$this->middleware = $middleware; | ||
} | ||
|
||
/** @return PromiseInterface<ResponseInterface> */ | ||
public function __invoke(ServerRequestInterface $request, callable $next = null): PromiseInterface | ||
{ | ||
return async(function () use ($request, $next) { | ||
Check failure on line 29 in src/Io/PsrMiddlewareAdapter.php GitHub Actions / PHPStan (PHP 7.4)
Check failure on line 29 in src/Io/PsrMiddlewareAdapter.php GitHub Actions / PHPStan (PHP 7.3)
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. async is not available for PHP < 7.4 but I wonder if that's really needed here. $deferred = new Deferred();
$deferred->resolve($this->middleware->process($request, new PsrAwaitRequestHandler($next)));
return $deferred->promise(); or even just return $this->middleware->process($request, new PsrAwaitRequestHandler($next)); since PSR-15 middlewares will most probably be blocking anyways!? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't think it's needed and like you said, with our commitment to PHP 7.4 support we can't really use it here for now (except building a workaround for PHP 7.4, but then we can just use the same workaround for all versions). |
||
return $this->middleware->process($request, new PsrAwaitRequestHandler($next)); | ||
})($request, $next); | ||
} | ||
} |
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.
This should(tm) only be a requirement for the tests to run, so I added it as dev-dependency
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.
Seems about right, we'd rather add a new dev-dependencies instead of a new requirement, as this only affects development and not all users 👍