You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
-[Middleware and request handler resolving](https://github.com/ellipsephp/dispatcher#middleware-and-request-handler-resolving)
13
-
-[Composing a dispatcher](https://github.com/ellipsephp/dispatcher#composing-a-dispatcher)
11
+
-[Using a dispatcher](#using-a-dispatcher)
12
+
-[Middleware and request handler resolving](#middleware-and-request-handler-resolving)
14
13
15
-
## Getting started
14
+
## Using a dispatcher
16
15
17
16
This package provides an `Ellipse\Dispatcher` class allowing to process a Psr-7 request through a Psr-15 middleware queue (First in first out order) before handling it with a Psr-15 request handler in order to create a Psr-7 response.
18
17
19
18
It is basically a request handler decorator wrapping a middleware queue around a request handler. Its constructor takes two parameters:
20
19
21
-
- a request handler instance implementing `Psr\Http\Server\RequestHandlerInterface`
22
-
- an array containing middleware instances implementing `Psr\Http\Server\MiddlewareInterface`
20
+
- a request handler object implementing `Psr\Http\Server\RequestHandlerInterface`
21
+
- an array containing middleware objects implementing `Psr\Http\Server\MiddlewareInterface`
23
22
24
23
The `Dispatcher` itself implements `RequestHandlerInterface` so a response is produced by using its `->handle()` method with a request. It also means it can be used as the request handler of another `Dispatcher`. Also, The same `Dispatcher` can be used multiple times to handle as many requests as needed.
25
24
26
-
Finally when a value of the given middleware queue is not an implementation of `MiddlewareInterface` an `Ellipse\Dispatcher\Exceptions\MiddlewareTypeException` is thrown. [Factory decorators](https://github.com/ellipsephp/dispatcher#middleware-and-request-handler-resolving) can be used to resolve some type of values as middleware.
25
+
Finally when a value of the given middleware queue is not an implementation of `MiddlewareInterface` an `Ellipse\Dispatcher\Exceptions\MiddlewareTypeException` is thrown. [Factory decorators](#middleware-and-request-handler-resolving) can be used to resolve some type of values as middleware.
27
26
28
27
```php
29
28
<?php
@@ -32,9 +31,6 @@ namespace App;
32
31
33
32
use Ellipse\Dispatcher;
34
33
35
-
// Get some incoming Psr-7 request.
36
-
$request = some_psr7_request_factory();
37
-
38
34
// Create a dispatcher using two middleware and a request handler.
39
35
$dispatcher = new Dispatcher(new SomeRequestHandler, [
40
36
new SomeMiddleware1,
@@ -61,9 +57,6 @@ namespace App;
61
57
62
58
use Ellipse\Dispatcher;
63
59
64
-
// Get some incoming Psr-7 request.
65
-
$request = some_psr7_request_factory();
66
-
67
60
// Create a dispatcher with two middleware.
68
61
$dispatcher = new Dispatcher(new SomeRequestHandler, [
Another common practice is to allow callables and class names registered in a container to be used as regular middleware/request handler.
85
+
A common practice is to allow callables and class names registered in a container to be used as regular middleware/request handler.
93
86
94
-
For this purpose this package also provides an `Ellipse\DispatcherFactory` class implementing `Ellipse\DispatcherFactoryInterface`, allowing to produce `Dispatcher` instances. Its `__invoke()` method takes any value as request handler and an optional middleware queue. When the given request handler is not an implementation of `RequestHandlerInterface`, an `Ellipse\Dispatcher\Exceptions\RequestHandlerTypeException` is thrown.
87
+
For this purpose this package also provides an `Ellipse\DispatcherFactory` class implementing `Ellipse\DispatcherFactoryInterface`, allowing to produce `Dispatcher` instances. Its `__invoke()` method takes any value as request handler and an optional middleware queue. An `Ellipse\Dispatcher\Exceptions\RequestHandlerTypeException` is thrown when the given request handler is not an implementation of `RequestHandlerInterface`.
The point of `DispatcherFactory` is to be decorated by other factories resolving the given values as Psr-15 implementations before delegating it the dispatcher creation. It is a starting point for such factory decorators (also called resolvers) which ensure the dispatcher creation fails nicely when any value is not resolved as a Psr-15 implementation by any decorator.
109
+
This class is not very useful by itself. The point of `DispatcherFactory` is to be decorated by other factories resolving the given values as Psr-15 implementations before delegating it the dispatcher creation. It is a starting point for such factory decorators (also called resolvers) which ensure the dispatcher creation fails nicely when any value is not resolved as a Psr-15 implementation by any decorator.
122
110
123
111
Here is an example of callable resolving using the `Ellipse\Dispatcher\CallableResolver` class from the [ellipse/dispatcher-callable](https://github.com/ellipsephp/dispatcher-callable) package:
124
112
@@ -130,9 +118,6 @@ namespace App;
130
118
use Ellipse\DispatcherFactory;
131
119
use Ellipse\Dispatcher\CallableResolver;
132
120
133
-
// Get some incoming Psr-7 request.
134
-
$request = some_psr7_request_factory();
135
-
136
121
// Get a decorated dispatcher factory.
137
122
$factory = new CallableResolver(new DispatcherFactory);
138
123
@@ -156,10 +141,8 @@ $response = $factory($handler, [$middleware, new SomeMiddleware])->handle($reque
156
141
Here is some ellipse packages providing resolvers for common resolving scenario:
157
142
158
143
-[ellipse/dispatcher-callable](https://github.com/ellipsephp/dispatcher-callable) allowing to use callables as Psr-15 implementations
159
-
-[ellipse/dispatcher-container](https://github.com/ellipsephp/dispatcher-container) allowing to use Psr-15 implementations retrieved from a [Psr-11 container](http://www.php-fig.org/psr/psr-11/meta/) using their class names
160
-
-[ellipse/dispatcher-controller](https://github.com/ellipsephp/dispatcher-controller) allowing to use controller definitions as Psr-15 request handler
161
-
162
-
Then it is up to you to build the dispatcher factory you need.
144
+
-[ellipse/dispatcher-container](https://github.com/ellipsephp/dispatcher-container) allowing to use Psr-15 implementation class names using a [Psr-11](https://www.php-fig.org/psr/psr-11/) container
145
+
-[ellipse/dispatcher-controller](https://github.com/ellipsephp/dispatcher-controller) allowing to use controller actions as Psr-15 request handlers using a [Psr-11](https://www.php-fig.org/psr/psr-11/) container
163
146
164
147
Here is an example of a class implementing `DispatcherFactoryInterface` in case you need to create a custom one:
165
148
@@ -182,22 +165,22 @@ class MyResolver implements DispatcherFactoryInterface
182
165
183
166
public function __invoke($handler, array $middleware = []): Dispatcher
184
167
{
185
-
// replace the handler with a ResolvedRequestHandler when the request handler should be resolved.
186
-
if ($this->shouldResolveHandler($handler)) {
168
+
// Replace the handler with a ResolvedRequestHandler when the request handler should be resolved.
169
+
$handler = $this->shouldResolveHandler($handler)
170
+
: new ResolvedRequestHandler($handler)
171
+
? $handler;
187
172
188
-
$handler = new ResolvedRequestHandler($handler);
173
+
// Replace middleware with a ResolvedMiddleware when a middleware should be resolved.
174
+
$middleware = array_map(function ($middleware) {
189
175
190
-
}
191
-
192
-
// Delegate the dispatcher creation to the decorated factory.
// Delegate the dispatcher creation to the decorated factory.
183
+
return ($this->delegate)($handler, $middleware);
201
184
}
202
185
203
186
private shouldResolveHandler($handler): bool
@@ -211,182 +194,3 @@ class MyResolver implements DispatcherFactoryInterface
211
194
}
212
195
}
213
196
```
214
-
215
-
The `MyResolver` can now decorate any implementation of `DispatcherFactoryInterface`:
216
-
217
-
```php
218
-
<?php
219
-
220
-
namespace App;
221
-
222
-
use Ellipse\DispatcherFactory;
223
-
use Ellipse\Dispatcher\CallableResolver;
224
-
225
-
$factory = new MyResolver(
226
-
new CallableResolver(
227
-
new DispatcherFactory
228
-
)
229
-
);
230
-
```
231
-
232
-
## Composing a dispatcher
233
-
234
-
Sometimes a dispatcher needs to be composed at runtime according to certain conditions. When routing for example: a solution is needed to build a dispatcher using different middleware queues and request handlers according to the matched route.
235
-
236
-
For this purpose this package provides an `Ellipse\Dispatcher\ResolverWithMiddleware` class. It can decorate any object implementing `DispatcherFactoryInterface`, wrapping a middleware queue around the dispatcher produced by the decorated factory.
237
-
238
-
Let's have an example using [FastRoute](https://github.com/nikic/FastRoute):
239
-
240
-
```php
241
-
<?php
242
-
243
-
namespace App;
244
-
245
-
use FastRoute\RouteCollector;
246
-
247
-
use Ellipse\DispatcherFactory;
248
-
use Ellipse\Dispatcher\ResolverWithMiddleware;
249
-
250
-
// Create a new DispatcherFactory.
251
-
$factory = new DispatcherFactory;
252
-
253
-
// Create a new FastRoute route collector.
254
-
$r = new RouteCollector(...);
255
-
256
-
// Those middleware will be wrapped around all the dispatchers.
257
-
$factory = new ResolverWithMiddleware($factory, [
258
-
new SomeMiddleware1,
259
-
new SomeMiddleware2,
260
-
]);
261
-
262
-
// The dispatcher matching the GET / route will use SomeMiddleware1, SomeMiddleware2 and RequestHandler1.
263
-
$r->get('/', $factory(new RequestHandler1));
264
-
265
-
// Let's have a first route group.
266
-
$r->group('/group1', function ($r) use ($factory) {
267
-
268
-
// SomeMiddleware3 is specific to this route group.
269
-
$factory = new ResolverWithMiddleware($factory, [new SomeMiddleware3]);
270
-
271
-
// The dispatcher matching the GET /group1/route1 route will use SomeMiddleware1, SomeMiddleware2, SomeMiddleware3 and RequestHandler2.
Create many new classes is cumbersome so `ResolverWithMiddleware` has a `->with()` method taking a middleware queue as parameter and returning a new `ResolverWithMiddleware` using it. The first factory can be decorated with the `Ellipse\Dispatcher\ComposableResolver` class implementing the same `->with()` method. The previous example can be written like this using the `->with()` method:
297
-
298
-
```php
299
-
<?php
300
-
301
-
namespace App;
302
-
303
-
use FastRoute\RouteCollector;
304
-
305
-
use Ellipse\DispatcherFactory;
306
-
use Ellipse\Dispatcher\ComposableResolver;
307
-
308
-
// Create a new ComposableResolver.
309
-
$factory = new ComposableResolver(new DispatcherFactory);
310
-
311
-
// Create a new FastRoute route collector.
312
-
$r = new RouteCollector(...);
313
-
314
-
// Those middleware will be wrapped around all the dispatchers.
315
-
$factory = $factory->with([
316
-
new SomeMiddleware1,
317
-
new SomeMiddleware2,
318
-
]);
319
-
320
-
// The dispatcher matching the GET / route will use SomeMiddleware1, SomeMiddleware2 and RequestHandler1.
321
-
$r->get('/', $factory(new RequestHandler1));
322
-
323
-
// Let's have a first route group.
324
-
$r->group('/group1', function ($r) use ($factory) {
325
-
326
-
// SomeMiddleware3 is specific to this route group.
327
-
$factory = $factory->with([new SomeMiddleware3]);
328
-
329
-
// The dispatcher matching the GET /group1/route1 route will use SomeMiddleware1, SomeMiddleware2, SomeMiddleware3 and RequestHandler2.
Of course, `ComposableResolver` and `ResolverWithMiddleware` can decorate any instance implementing `DispatcherFactoryInterface`. For example the `CallableResolver` class from the [ellipse/dispatcher-callable](https://github.com/ellipsephp/dispatcher-callable) package:
355
-
356
-
```php
357
-
<?php
358
-
359
-
namespace App;
360
-
361
-
use FastRoute\RouteCollector;
362
-
363
-
use Ellipse\DispatcherFactory;
364
-
use Ellipse\Dispatcher\ComposableResolver;
365
-
use Ellipse\Dispatcher\CallableResolver;
366
-
367
-
// Create a new ComposableResolver resolving callables.
368
-
$factory = new ComposableResolver(
369
-
new CallableResolver(
370
-
new DispatcherFactory
371
-
)
372
-
);
373
-
374
-
// Create a new FastRoute route collector.
375
-
$r = new RouteCollector(...);
376
-
377
-
// Callables can be used as Psr-15 middleware.
378
-
$factory = $factory->with([
379
-
function ($request, $handler) {
380
-
381
-
// This callable behave like a Psr-15 middleware.
382
-
383
-
},
384
-
]);
385
-
386
-
// Callables can be used as request handlers too.
387
-
$r->get('/', $factory(function ($request) {
388
-
389
-
// This callable behave like a Psr-15 request handler.
0 commit comments