Update documentation for QueueRequestHandler

This commit is contained in:
Sebastian Meyer 2024-07-12 15:29:35 +02:00
parent 3554cc7a0a
commit 29fed99ec0
11 changed files with 368 additions and 29 deletions

View File

@ -3,3 +3,108 @@
QueueRequestHandler
###################
.. sidebar:: Table of Contents
.. contents::
The `QueueRequestHandler` is the core piece of this package. It fetches incoming HTTP requests, passes them through a
queue of middlewares and finally sends the response back to the client. It also catches any exceptions not handled by
a middleware and turns them into a proper HTTP error response.
The `QueueRequestHandler` implements the
`Psr\Http\Server\RequestHandlerInterface <https://www.php-fig.org/psr/psr-15/#21-psrhttpserverrequesthandlerinterface>`_
following PHP-FIG's recommendation `PSR-15: HTTP Server Request Handlers <https://www.php-fig.org/psr/psr-15/>`_.
For a minimal working example have a look at :doc:`../usage/usage`.
Properties
==========
The `QueueRequestHandler` has three **read-only** properties. They are initially set at instantiation and can be
directly accessed from the object via magic methods (e.g. `$requestHandler->queue`).
Middleware Queue
----------------
The queue of middlewares can be accessed as `QueueRequestHandler::queue` and offers a handy API to `enqueue()`,
`dequeue()` or otherwise manipulate its contents. All middlewares must implement `Psr\Http\Server\MiddlewareInterface`.
Have a look at :doc:`middlewarequeue` for more details.
When instantiating a `QueueRequestHandler` the queue defaults to being empty. But you can optionally pass an iterable
set of middlewares to the constructor which are then put into the queue. To demonstrate, the following examples both
have exactly the same result.
Examples:
.. code-block:: php
use OCC\PSR15\QueueRequestHandler;
$middlewares = [
new MiddlewareOne(),
new MiddlewareTwo()
];
$requestHandler = new QueueRequestHandler($middlewares);
.. code-block:: php
use OCC\PSR15\QueueRequestHandler;
$requestHandler = new QueueRequestHandler();
$requestHandler->queue->enqueue(new MiddlewareOne());
$requestHandler->queue->enqueue(new MiddlewareTwo());
HTTP Server Request
-------------------
The server request is always available as `QueueRequestHandler::request`. It follows PHP-FIG's standard recommendation
`PSR-7: HTTP Message Interfaces <https://www.php-fig.org/psr/psr-7/>`_ and implements the
`Psr\Http\Message\ServerRequestInterface <https://www.php-fig.org/psr/psr-7/#321-psrhttpmessageserverrequestinterface>`_.
When instantiating a `QueueRequestHandler` the `$request` property is initially set by fetching the actual server
request data from superglobals. The property is reset each time the request is passed through a middleware and thus
always represents the current state of the request.
HTTP Response
-------------
The response can be read as `QueueRequestHandler::response`. It also follows PHP-FIG's standard recommendation
`PSR-7: HTTP Message Interfaces <https://www.php-fig.org/psr/psr-7/>`_ and implements the
`Psr\Http\Message\ResponseInterface <https://www.php-fig.org/psr/psr-7/#33-psrhttpmessageresponseinterface>`_.
When instantiating a `QueueRequestHandler` the `$response` property is initially set as a blank HTTP response with
status code `200`. The property is reset each time the response is passed through a middleware and thus
always represents the latest state of the response.
Both, request and response, use the awesome implementations of `Guzzle <https://github.com/guzzle/psr7>`_.
Methods
=======
The `QueueRequestHandler` provides two public API methods, :php:method:`OCC\PSR15\QueueRequestHandler::handle()` and
:php:method:`OCC\PSR15\QueueRequestHandler::respond()`. As their names suggest, the former handles the server request
while the latter sends the response back to the client. Invoking the request handler object directly does the same as
calling the `handle()` method.
Handling a Server Request
-------------------------
After adding at least one middleware to the queue, you can start handling a request by simply calling
:php:method:`OCC\PSR15\QueueRequestHandler::handle()`. Optionally, you can pass a request object as argument, but since
the actual server request was already fetched in the constructor and will be used by default, most of the time you
don't need to. All request objects must implement `Psr\Http\Message\ServerRequestInterface`.
The `handle()` method returns the final response after passing it through all middlewares. The response object always
implements `Psr\Http\Message\ResponseInterface`.
In case of an error the request handler catches any exception and creates a response with the exception code as status
code (if it's within the valid range of HTTP status codes, otherwise it's set to `500 (Internal Server Error)`), and
the exception message as body.
Sending the Response
--------------------
Sending the final response to the client is as easy as calling :php:method:`OCC\PSR15\QueueRequestHandler::respond()`.
Optionally, you can provide an exit code as argument (an integer in the range `0` to `254`). If you do so, script
execution is stopped after sending out the response and the given exit status is set. The status `0` means the request
was handled successfully, every other status is considered an error.

View File

@ -20,7 +20,7 @@ The abstract middleware already implements a complete middleware, but it will ju
anything. In order to have it do something, we need to implement our own :php:method:`OCC\PSR15\AbstractMiddleware::processRequest()`
or :php:method:`OCC\PSR15\AbstractMiddleware::processResponse()` method, or both of them.
The logic here is the same as with every `PSR-15: HTTP Server Request Handler <https://www.php-fig.org/psr/psr-15/>`_
The logic here is the same as with every `PSR-15: HTTP Server Request Handlers <https://www.php-fig.org/psr/psr-15/>`_
middleware: The request gets passed through all middlewares' `processRequest()` methods in order of their addition to
the queue, then a response is created and passed through all `processResponse()` methods, **but in reverse order**! So
the first middleware in the queue gets the request first, but the response last.
@ -149,7 +149,7 @@ Diving Deeper
=============
To familiarize yourself with the FIFO principle of the middleware queue, you can try to exchange the two lines adding
the middlewares to the queue, i.e. adding `MiddlewareTwo` first and `MiddlewareOne` second. This will result in an HTTP
the middlewares to the queue, i.e. add `MiddlewareTwo` first and `MiddlewareOne` second. This will result in an HTTP
response with status code `500 (Internal Server Error)`.
This is exactly what we intended: Have a look at `MiddlewareTwo::processResponse()` again! If `$lastMiddlewarePassed`

View File

@ -298,9 +298,9 @@
<aside class="phpdocumentor-element-found-in">
<abbr class="phpdocumentor-element-found-in__file" title="src/AbstractMiddleware.php"><a href="files/src-abstractmiddleware.html"><abbr title="src/AbstractMiddleware.php">AbstractMiddleware.php</abbr></a></abbr>
:
<span class="phpdocumentor-element-found-in__line">105</span>
<span class="phpdocumentor-element-found-in__line">103</span>
<a href="classes/OCC-PSR15-AbstractMiddleware.html#source-view.105" class="phpdocumentor-element-found-in__source" data-line="105" data-modal="source-view" data-src="files/src/AbstractMiddleware.php.txt"></a>
<a href="classes/OCC-PSR15-AbstractMiddleware.html#source-view.103" class="phpdocumentor-element-found-in__source" data-line="103" data-modal="source-view" data-src="files/src/AbstractMiddleware.php.txt"></a>
</aside>
<p class="phpdocumentor-summary">Allow the middleware to be invoked directly.</p>
@ -310,8 +310,6 @@
<span class="phpdocumentor-signature__final">final</span> <span class="phpdocumentor-signature__name">__invoke</span><span>(</span><span class="phpdocumentor-signature__argument"><span class="phpdocumentor-signature__argument__return-type"><abbr title="\Psr\Http\Message\ServerRequestInterface">ServerRequestInterface</abbr>&nbsp;</span><span class="phpdocumentor-signature__argument__name">$request</span></span><span class="phpdocumentor-signature__argument"><span>, </span><span class="phpdocumentor-signature__argument__return-type"><abbr title="\Psr\Http\Server\RequestHandlerInterface">RequestHandlerInterface</abbr>&nbsp;</span><span class="phpdocumentor-signature__argument__name">$handler</span></span><span>)</span><span> : </span><span class="phpdocumentor-signature__response_type"><abbr title="\Psr\Http\Message\ResponseInterface">ResponseInterface</abbr></span></code>
<div class="phpdocumentor-label-line">
<div class="phpdocumentor-label phpdocumentor-label--success"><span>API</span><span>Yes</span></div>
</div>

View File

@ -442,9 +442,9 @@
<aside class="phpdocumentor-element-found-in">
<abbr class="phpdocumentor-element-found-in__file" title="src/QueueRequestHandler.php"><a href="files/src-queuerequesthandler.html"><abbr title="src/QueueRequestHandler.php">QueueRequestHandler.php</abbr></a></abbr>
:
<span class="phpdocumentor-element-found-in__line">216</span>
<span class="phpdocumentor-element-found-in__line">225</span>
<a href="classes/OCC-PSR15-QueueRequestHandler.html#source-view.216" class="phpdocumentor-element-found-in__source" data-line="216" data-modal="source-view" data-src="files/src/QueueRequestHandler.php.txt"></a>
<a href="classes/OCC-PSR15-QueueRequestHandler.html#source-view.225" class="phpdocumentor-element-found-in__source" data-line="225" data-modal="source-view" data-src="files/src/QueueRequestHandler.php.txt"></a>
</aside>
<p class="phpdocumentor-summary">Create a queue-based PSR-15 HTTP Server Request Handler.</p>
@ -490,9 +490,9 @@
<aside class="phpdocumentor-element-found-in">
<abbr class="phpdocumentor-element-found-in__file" title="src/QueueRequestHandler.php"><a href="files/src-queuerequesthandler.html"><abbr title="src/QueueRequestHandler.php">QueueRequestHandler.php</abbr></a></abbr>
:
<span class="phpdocumentor-element-found-in__line">232</span>
<span class="phpdocumentor-element-found-in__line">239</span>
<a href="classes/OCC-PSR15-QueueRequestHandler.html#source-view.232" class="phpdocumentor-element-found-in__source" data-line="232" data-modal="source-view" data-src="files/src/QueueRequestHandler.php.txt"></a>
<a href="classes/OCC-PSR15-QueueRequestHandler.html#source-view.239" class="phpdocumentor-element-found-in__source" data-line="239" data-modal="source-view" data-src="files/src/QueueRequestHandler.php.txt"></a>
</aside>
<p class="phpdocumentor-summary">Allow the request handler to be invoked directly.</p>
@ -502,8 +502,6 @@
<span class="phpdocumentor-signature__name">__invoke</span><span>(</span><span class="phpdocumentor-signature__argument"><span>[</span><span class="phpdocumentor-signature__argument__return-type"><abbr title="\Psr\Http\Message\ServerRequestInterface">ServerRequestInterface</abbr>|null&nbsp;</span><span class="phpdocumentor-signature__argument__name">$request</span><span> = </span><span class="phpdocumentor-signature__argument__default-value">null</span><span> ]</span></span><span>)</span><span> : </span><span class="phpdocumentor-signature__response_type"><abbr title="\Psr\Http\Message\ResponseInterface">ResponseInterface</abbr></span></code>
<div class="phpdocumentor-label-line">
<div class="phpdocumentor-label phpdocumentor-label--success"><span>API</span><span>Yes</span></div>
</div>
@ -606,9 +604,9 @@
<aside class="phpdocumentor-element-found-in">
<abbr class="phpdocumentor-element-found-in__file" title="src/QueueRequestHandler.php"><a href="files/src-queuerequesthandler.html"><abbr title="src/QueueRequestHandler.php">QueueRequestHandler.php</abbr></a></abbr>
:
<span class="phpdocumentor-element-found-in__line">140</span>
<span class="phpdocumentor-element-found-in__line">141</span>
<a href="classes/OCC-PSR15-QueueRequestHandler.html#source-view.140" class="phpdocumentor-element-found-in__source" data-line="140" data-modal="source-view" data-src="files/src/QueueRequestHandler.php.txt"></a>
<a href="classes/OCC-PSR15-QueueRequestHandler.html#source-view.141" class="phpdocumentor-element-found-in__source" data-line="141" data-modal="source-view" data-src="files/src/QueueRequestHandler.php.txt"></a>
</aside>
<p class="phpdocumentor-summary">Return the current response to the client.</p>
@ -630,7 +628,8 @@
: <span class="phpdocumentor-signature__argument__return-type">int|null</span>
= <span class="phpdocumentor-signature__argument__default-value">null</span> </dt>
<dd class="phpdocumentor-argument-list__definition">
<section class="phpdocumentor-description"><p>Exit code after sending out the response or NULL to continue</p>
<section class="phpdocumentor-description"><p>Exit status after sending out the response or NULL to continue</p>
<p>Must be in the range 0 to 254. The status 0 is used to terminate the program successfully.</p>
</section>
</dd>

View File

@ -99,8 +99,6 @@ abstract class AbstractMiddleware implements MiddlewareInterface
* @param RequestHandler $handler The request handler to delegate to
*
* @return Response The response object
*
* @api
*/
final public function __invoke(ServerRequest $request, RequestHandler $handler): Response
{

View File

@ -120,7 +120,6 @@ class QueueRequestHandler implements RequestHandler
$exception->getMessage()
)
);
$this->respond(1);
}
}
return $this->response;
@ -129,7 +128,9 @@ class QueueRequestHandler implements RequestHandler
/**
* Return the current response to the client.
*
* @param ?int $exitCode Exit code after sending out the response or NULL to continue
* @param ?int $exitCode Exit status after sending out the response or NULL to continue
*
* Must be in the range 0 to 254. The status 0 is used to terminate the program successfully.
*
* @return void
*
@ -166,6 +167,14 @@ class QueueRequestHandler implements RequestHandler
}
echo $this->response->getBody();
if (!is_null($exitCode)) {
$options = [
'options' => [
'default' => 1,
'min_range' => 0,
'max_range' => 254
]
];
$exitCode = filter_var($exitCode, FILTER_VALIDATE_INT, $options);
exit($exitCode);
}
}
@ -226,8 +235,6 @@ class QueueRequestHandler implements RequestHandler
* @param ?ServerRequest $request The PSR-7 server request to handle
*
* @return Response A PSR-7 compatible HTTP response
*
* @api
*/
public function __invoke(?ServerRequest $request = null): Response
{

View File

@ -171,7 +171,20 @@ in other projects.</p>
<li class="toc-item">
<a href="guides/overview/queuerequesthandler.html#queuerequesthandler">QueueRequestHandler</a>
<ul class="section-level-1">
<li class="toc-item">
<a href="guides/overview/queuerequesthandler.html#properties">Properties</a>
</li>
<li class="toc-item">
<a href="guides/overview/queuerequesthandler.html#methods">Methods</a>
</li>
</ul>
</li>
<li class="toc-item">

View File

@ -153,6 +153,220 @@
<div class="section" id="queuerequesthandler">
<h1>QueueRequestHandler</h1>
<div class="admonition-wrapper">
<div class="admonition admonition-sidebar"><p class="sidebar-title">Table of Contents</p>
<div class="contents">
<ul class="phpdocumentor-list">
<li class="toc-item">
<a href="guides/overview/queuerequesthandler.html#properties">Properties</a>
<ul class="section-level-2">
<li class="toc-item">
<a href="guides/overview/queuerequesthandler.html#middleware-queue">Middleware Queue</a>
</li>
<li class="toc-item">
<a href="guides/overview/queuerequesthandler.html#http-server-request">HTTP Server Request</a>
</li>
<li class="toc-item">
<a href="guides/overview/queuerequesthandler.html#http-response">HTTP Response</a>
</li>
</ul>
</li>
<li class="toc-item">
<a href="guides/overview/queuerequesthandler.html#methods">Methods</a>
<ul class="section-level-2">
<li class="toc-item">
<a href="guides/overview/queuerequesthandler.html#handling-a-server-request">Handling a Server Request</a>
</li>
<li class="toc-item">
<a href="guides/overview/queuerequesthandler.html#sending-the-response">Sending the Response</a>
</li>
</ul>
</li>
</ul>
</div>
</div>
</div>
<p>The <code>QueueRequestHandler</code>
is the core piece of this package. It fetches incoming HTTP requests, passes them through a
queue of middlewares and finally sends the response back to the client. It also catches any exceptions not handled by
a middleware and turns them into a proper HTTP error response.</p>
<p>The <code>QueueRequestHandler</code>
implements the
<a href="https://www.php-fig.org/psr/psr-15/#21-psrhttpserverrequesthandlerinterface">Psr\Http\Server\RequestHandlerInterface</a>
following PHP-FIG&#039;s recommendation <a href="https://www.php-fig.org/psr/psr-15/">PSR-15: HTTP Server Request Handlers</a>.</p>
<p>For a minimal working example have a look at <a href="guides/usage/usage.html">Usage</a>.</p>
<div class="section" id="properties">
<h2>Properties</h2>
<p>The <code>QueueRequestHandler</code>
has three <strong>read-only</strong>
properties. They are initially set at instantiation and can be
directly accessed from the object via magic methods (e.g. <code>$requestHandler-&gt;queue</code>
).</p>
<div class="section" id="middleware-queue">
<h3>Middleware Queue</h3>
<p>The queue of middlewares can be accessed as <code>QueueRequestHandler::queue</code>
and offers a handy API to <code>enqueue()</code>
,
<code>dequeue()</code>
or otherwise manipulate its contents. All middlewares must implement <code>Psr\Http\Server\MiddlewareInterface</code>
.
Have a look at <a href="guides/overview/middlewarequeue.html">MiddlewareQueue</a> for more details.</p>
<p>When instantiating a <code>QueueRequestHandler</code>
the queue defaults to being empty. But you can optionally pass an iterable
set of middlewares to the constructor which are then put into the queue. To demonstrate, the following examples both
have exactly the same result.</p>
<blockquote>
<p>Examples:</p>
<pre><code class="language-php">use OCC\PSR15\QueueRequestHandler;
$middlewares = [
new MiddlewareOne(),
new MiddlewareTwo()
];
$requestHandler = new QueueRequestHandler($middlewares);</code></pre>
<pre><code class="language-php">use OCC\PSR15\QueueRequestHandler;
$requestHandler = new QueueRequestHandler();
$requestHandler-&gt;queue-&gt;enqueue(new MiddlewareOne());
$requestHandler-&gt;queue-&gt;enqueue(new MiddlewareTwo());</code></pre>
</blockquote>
</div>
<div class="section" id="http-server-request">
<h3>HTTP Server Request</h3>
<p>The server request is always available as <code>QueueRequestHandler::request</code>
. It follows PHP-FIG&#039;s standard recommendation
<a href="https://www.php-fig.org/psr/psr-7/">PSR-7: HTTP Message Interfaces</a> and implements the
<a href="https://www.php-fig.org/psr/psr-7/#321-psrhttpmessageserverrequestinterface">Psr\Http\Message\ServerRequestInterface</a>.</p>
<p>When instantiating a <code>QueueRequestHandler</code>
the <code>$request</code>
property is initially set by fetching the actual server
request data from superglobals. The property is reset each time the request is passed through a middleware and thus
always represents the current state of the request.</p>
</div>
<div class="section" id="http-response">
<h3>HTTP Response</h3>
<p>The response can be read as <code>QueueRequestHandler::response</code>
. It also follows PHP-FIG&#039;s standard recommendation
<a href="https://www.php-fig.org/psr/psr-7/">PSR-7: HTTP Message Interfaces</a> and implements the
<a href="https://www.php-fig.org/psr/psr-7/#33-psrhttpmessageresponseinterface">Psr\Http\Message\ResponseInterface</a>.</p>
<p>When instantiating a <code>QueueRequestHandler</code>
the <code>$response</code>
property is initially set as a blank HTTP response with
status code <code>200</code>
. The property is reset each time the response is passed through a middleware and thus
always represents the latest state of the response.</p>
<p>Both, request and response, use the awesome implementations of <a href="https://github.com/guzzle/psr7">Guzzle</a>.</p>
</div>
</div>
<div class="section" id="methods">
<h2>Methods</h2>
<p>The <code>QueueRequestHandler</code>
provides two public API methods, <a href="classes/OCC-PSR15-QueueRequestHandler.html#method_handle"><abbr title="\OCC\PSR15\QueueRequestHandler::handle()">QueueRequestHandler::handle()</abbr></a>
and
<a href="classes/OCC-PSR15-QueueRequestHandler.html#method_respond"><abbr title="\OCC\PSR15\QueueRequestHandler::respond()">QueueRequestHandler::respond()</abbr></a>
. As their names suggest, the former handles the server request
while the latter sends the response back to the client. Invoking the request handler object directly does the same as
calling the <code>handle()</code>
method.</p>
<div class="section" id="handling-a-server-request">
<h3>Handling a Server Request</h3>
<p>After adding at least one middleware to the queue, you can start handling a request by simply calling
<a href="classes/OCC-PSR15-QueueRequestHandler.html#method_handle"><abbr title="\OCC\PSR15\QueueRequestHandler::handle()">QueueRequestHandler::handle()</abbr></a>
. Optionally, you can pass a request object as argument, but since
the actual server request was already fetched in the constructor and will be used by default, most of the time you
don&#039;t need to. All request objects must implement <code>Psr\Http\Message\ServerRequestInterface</code>
.</p>
<p>The <code>handle()</code>
method returns the final response after passing it through all middlewares. The response object always
implements <code>Psr\Http\Message\ResponseInterface</code>
.</p>
<p>In case of an error the request handler catches any exception and creates a response with the exception code as status
code (if it&#039;s within the valid range of HTTP status codes, otherwise it&#039;s set to <code>500 (Internal Server Error)</code>
), and
the exception message as body.</p>
</div>
<div class="section" id="sending-the-response">
<h3>Sending the Response</h3>
<p>Sending the final response to the client is as easy as calling <a href="classes/OCC-PSR15-QueueRequestHandler.html#method_respond"><abbr title="\OCC\PSR15\QueueRequestHandler::respond()">QueueRequestHandler::respond()</abbr></a>
.
Optionally, you can provide an exit code as argument (an integer in the range <code>0</code>
to <code>254</code>
). If you do so, script
execution is stopped after sending out the response and the given exit status is set. The status <code>0</code>
means the request
was handled successfully, every other status is considered an error.</p>
</div>
</div>
</div>
</div>

View File

@ -205,7 +205,7 @@ or <a href="classes/OCC-PSR15-AbstractMiddleware.html#method_processResponse"><a
method, or both of them.</p>
<p>The logic here is the same as with every <a href="https://www.php-fig.org/psr/psr-15/">PSR-15: HTTP Server Request Handler</a>
<p>The logic here is the same as with every <a href="https://www.php-fig.org/psr/psr-15/">PSR-15: HTTP Server Request Handlers</a>
middleware: The request gets passed through all middlewares&#039; <code>processRequest()</code>
methods in order of their addition to
the queue, then a response is created and passed through all <code>processResponse()</code>
@ -348,7 +348,7 @@ $requestHandler-&gt;respond();
<p>To familiarize yourself with the FIFO principle of the middleware queue, you can try to exchange the two lines adding
the middlewares to the queue, i.e. adding <code>MiddlewareTwo</code>
the middlewares to the queue, i.e. add <code>MiddlewareTwo</code>
first and <code>MiddlewareOne</code>
second. This will result in an HTTP
response with status code <code>500 (Internal Server Error)</code>

View File

@ -99,8 +99,6 @@ abstract class AbstractMiddleware implements MiddlewareInterface
* @param RequestHandler $handler The request handler to delegate to
*
* @return Response The response object
*
* @api
*/
final public function __invoke(ServerRequest $request, RequestHandler $handler): Response
{

View File

@ -120,7 +120,6 @@ class QueueRequestHandler implements RequestHandler
$exception->getMessage()
)
);
$this->respond(1);
}
}
return $this->response;
@ -129,7 +128,9 @@ class QueueRequestHandler implements RequestHandler
/**
* Return the current response to the client.
*
* @param ?int $exitCode Exit code after sending out the response or NULL to continue
* @param ?int $exitCode Exit status after sending out the response or NULL to continue
*
* Must be in the range 0 to 254. The status 0 is used to terminate the program successfully.
*
* @return void
*
@ -166,6 +167,14 @@ class QueueRequestHandler implements RequestHandler
}
echo $this->response->getBody();
if (!is_null($exitCode)) {
$options = [
'options' => [
'default' => 1,
'min_range' => 0,
'max_range' => 254
]
];
$exitCode = filter_var($exitCode, FILTER_VALIDATE_INT, $options);
exit($exitCode);
}
}
@ -226,8 +235,6 @@ class QueueRequestHandler implements RequestHandler
* @param ?ServerRequest $request The PSR-7 server request to handle
*
* @return Response A PSR-7 compatible HTTP response
*
* @api
*/
public function __invoke(?ServerRequest $request = null): Response
{