Skip to content

Commit 74c089c

Browse files
authored
Readme and cleanup (#25)
1 parent 08a0356 commit 74c089c

8 files changed

+143
-22
lines changed

README.md

+66-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
[![static analysis](https://github.com/yiisoft/middleware-dispatcher/workflows/static%20analysis/badge.svg)](https://github.com/yiisoft/middleware-dispatcher/actions?query=workflow%3A%22static+analysis%22)
1616
[![type-coverage](https://shepherd.dev/github/yiisoft/middleware-dispatcher/coverage.svg)](https://shepherd.dev/github/yiisoft/middleware-dispatcher)
1717

18-
The package is a [PSR-15](https://www.php-fig.org/psr/psr-15/) middleware dispatcher.
18+
The package is a [PSR-15](https://www.php-fig.org/psr/psr-15/) middleware dispatcher. Given a set of middleware and a
19+
request instance, dispatcher executes it producing a response instance.
1920

2021
## Requirements
2122

@@ -31,6 +32,70 @@ composer require yiisoft/middleware-dispatcher --prefer-dist
3132

3233
## General usage
3334

35+
To use a dispatcher, you need to create it first:
36+
37+
```php
38+
use Yiisoft\Middleware\Dispatcher\MiddlewareDispatcher;
39+
use Yiisoft\Middleware\Dispatcher\MiddlewareFactory;
40+
use Yiisoft\Middleware\Dispatcher\MiddlewareStack;
41+
42+
$dispatcher = new MiddlewareDispatcher(
43+
new MiddlewareFactory($diContainer),
44+
new MiddlewareStack($eventDispatcher)
45+
);
46+
```
47+
48+
In the above `$diContainer` is an instance of [PSR-11](https://www.php-fig.org/psr/psr-11/) `\Psr\Container\ContainerInterface`
49+
and `$eventDispatcher` is an instance of [PSR-14](https://www.php-fig.org/psr/psr-14/) `Psr\EventDispatcher\EventDispatcherInterface`.
50+
51+
After dispatcher instance obtained, it should be fed with some middleware:
52+
53+
```php
54+
$dispatcher = $dispatcher->withMiddlewares([
55+
static function (): ResponseInterface {
56+
return new Response(418);
57+
},
58+
]);
59+
```
60+
61+
In the above we have used a callback. Overall the following options are available:
62+
63+
- A controller handler action in format `[TestController::class, 'index']`. `TestController` instance will be created and
64+
`index()` method will be executed.
65+
- A name of PSR-15 middleware class. The middleware instance will be obtained from container executed.
66+
- A function returning a middleware such as
67+
```php
68+
static function (): MiddlewareInterface {
69+
return new TestMiddleware();
70+
}
71+
```
72+
The middleware returned will be executed.
73+
- A callback `function(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface`.
74+
75+
For handler action and callable typed parameters are automatically injected using dependency injection container.
76+
Current request and handler could be obtained by type-hinting for `ServerRequestInterface` and `RequestHandlerInterface`.
77+
78+
After middleware set is defined, you can do the dispatching:
79+
80+
```php
81+
$request = new ServerRequest('GET', '/teapot');
82+
$response = $dispatcher->dispatch($request, $this->getRequestHandler());
83+
```
84+
85+
Given a request dispatcher executes middleware in the set and produces response. Last specified middleware will be
86+
executed first. For each middleware
87+
`\Yiisoft\Middleware\Dispatcher\Event\BeforeMiddleware` and `\Yiisoft\Middleware\Dispatcher\Event\AfterMiddleware`
88+
events are triggered.
89+
90+
### Customizing dispatcher
91+
92+
There are two possibilities customizing middleare dispatcher:
93+
94+
1. Providing custom implementation of `MiddlewareFactoryInterface`. There you can introduce custom syntax for defining
95+
middleware or feed middleware created with additional data.
96+
2. Providing custom implementation of `MiddlewarePiplineInterface`. There you can customize in which order and
97+
how exactly middleware are executed.
98+
3499
## Testing
35100

36101
### Unit testing

src/Event/AfterMiddleware.php

+7-3
Original file line numberDiff line numberDiff line change
@@ -8,29 +8,33 @@
88
use Psr\Http\Server\MiddlewareInterface;
99

1010
/**
11-
* AfterMiddleware event is raised after a middleware was executed
11+
* AfterMiddleware event is raised after a middleware was executed.
1212
*/
1313
final class AfterMiddleware
1414
{
1515
private MiddlewareInterface $middleware;
1616
private ?ResponseInterface $response;
1717

18+
/**
19+
* @param MiddlewareInterface $middleware Middleware that was executed.
20+
* @param ResponseInterface|null $response Response generated by middleware or null in case there was an error.
21+
*/
1822
public function __construct(MiddlewareInterface $middleware, ?ResponseInterface $response)
1923
{
2024
$this->middleware = $middleware;
2125
$this->response = $response;
2226
}
2327

2428
/**
25-
* @return MiddlewareInterface middleware that was executed
29+
* @return MiddlewareInterface Middleware that was executed.
2630
*/
2731
public function getMiddleware(): MiddlewareInterface
2832
{
2933
return $this->middleware;
3034
}
3135

3236
/**
33-
* @return ResponseInterface|null response generated by middleware or null in case there was an error
37+
* @return ResponseInterface|null Response generated by middleware or null in case there was an error.
3438
*/
3539
public function getResponse(): ?ResponseInterface
3640
{

src/Event/BeforeMiddleware.php

+13
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,35 @@
77
use Psr\Http\Message\ServerRequestInterface;
88
use Psr\Http\Server\MiddlewareInterface;
99

10+
/**
11+
* AfterMiddleware event is raised before executing a middleware.
12+
*/
1013
final class BeforeMiddleware
1114
{
1215
private MiddlewareInterface $middleware;
1316
private ServerRequestInterface $request;
1417

18+
/**
19+
* @param MiddlewareInterface $middleware Middleware to be executed.
20+
* @param ServerRequestInterface $request Request to be passed to the middleware.
21+
*/
1522
public function __construct(MiddlewareInterface $middleware, ServerRequestInterface $request)
1623
{
1724
$this->middleware = $middleware;
1825
$this->request = $request;
1926
}
2027

28+
/**
29+
* @return MiddlewareInterface Middleware to be executed.
30+
*/
2131
public function getMiddleware(): MiddlewareInterface
2232
{
2333
return $this->middleware;
2434
}
2535

36+
/**
37+
* @return ServerRequestInterface Request to be passed to the middleware.
38+
*/
2639
public function getRequest(): ServerRequestInterface
2740
{
2841
return $this->request;

src/InvalidMiddlewareDefinitionException.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ private function convertDefinitionToString($middlewareDefinition): ?string
4343

4444
if (is_array($middlewareDefinition)) {
4545
$items = $middlewareDefinition;
46-
foreach ($middlewareDefinition as $key => $item) {
46+
foreach ($middlewareDefinition as $item) {
4747
if (!is_string($item)) {
4848
return null;
4949
}

src/MiddlewareDispatcher.php

+21-5
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@ public function __construct(MiddlewareFactoryInterface $middlewareFactory, Middl
3131
$this->pipeline = $pipeline;
3232
}
3333

34+
/**
35+
* Dispatch request through middleware to get response.
36+
*
37+
* @param ServerRequestInterface $request Request to pass to middleware.
38+
* @param RequestHandlerInterface $fallbackHandler Handler to use in case no middleware produced response.
39+
*/
3440
public function dispatch(ServerRequestInterface $request, RequestHandlerInterface $fallbackHandler): ResponseInterface
3541
{
3642
if ($this->pipeline->isEmpty()) {
@@ -41,13 +47,20 @@ public function dispatch(ServerRequestInterface $request, RequestHandlerInterfac
4147
}
4248

4349
/**
44-
* Returns new instance with middleware handlers replaced.
50+
* Returns new instance with middleware handlers replaced with the ones provided.
4551
* Last specified handler will be executed first.
4652
*
47-
* @param array[]|callable[]|string[] $middlewareDefinitions Each array element is a name of PSR-15 middleware,
48-
* a callable with `function(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface`
49-
* signature or a handler action (an array of [handlerClass, handlerMethod]). For handler action and callable
50-
* typed parameters are automatically injected using dependency injection container passed to the route.
53+
* @param array[]|callable[]|string[] $middlewareDefinitions Each array element is:
54+
*
55+
* - A name of PSR-15 middleware class. The middleware instance will be obtained from container executed.
56+
* - A callable with `function(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface`
57+
* signature.
58+
* - A controller handler action in format `[TestController::class, 'index']`. `TestController` instance will
59+
* be created and `index()` method will be executed.
60+
* - A function returning a middleware. The middleware returned will be executed.
61+
*
62+
* For handler action and callable
63+
* typed parameters are automatically injected using dependency injection container.
5164
* Current request and handler could be obtained by type-hinting for {@see ServerRequestInterface}
5265
* and {@see RequestHandlerInterface}.
5366
*
@@ -62,6 +75,9 @@ public function withMiddlewares(array $middlewareDefinitions): self
6275
return $clone;
6376
}
6477

78+
/**
79+
* @return bool Whether there are middleware defined in the dispatcher.
80+
*/
6581
public function hasMiddlewares(): bool
6682
{
6783
return $this->middlewareDefinitions !== [];

src/MiddlewareFactory.php

+17-4
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,33 @@
1616
use function is_array;
1717
use function is_string;
1818

19+
/**
20+
* Creates a PSR-15 middleware based on the definition provided.
21+
*/
1922
final class MiddlewareFactory implements MiddlewareFactoryInterface
2023
{
2124
private ContainerInterface $container;
2225

26+
/**
27+
* @param ContainerInterface $container Container to use for resolving definitions.
28+
*/
2329
public function __construct(ContainerInterface $container)
2430
{
2531
$this->container = $container;
2632
}
2733

2834
/**
29-
* @param array|callable|string $middlewareDefinition A name of PSR-15 middleware, a callable with
30-
* `function(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface` signature or
31-
* a handler action (an array of [handlerClass, handlerMethod]). For handler action and callable typed parameters
32-
* are automatically injected using dependency injection container passed to the route.
35+
* @param array|callable|string $middlewareDefinition Middleware definition in one of the following formats:
36+
*
37+
* - A name of PSR-15 middleware class. The middleware instance will be obtained from container and executed.
38+
* - A callable with `function(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface`
39+
* signature.
40+
* - A controller handler action in format `[TestController::class, 'index']`. `TestController` instance will
41+
* be created and `index()` method will be executed.
42+
* - A function returning a middleware. The middleware returned will be executed.
43+
*
44+
* For handler action and callable
45+
* typed parameters are automatically injected using dependency injection container.
3346
* Current request and handler could be obtained by type-hinting for {@see ServerRequestInterface}
3447
* and {@see RequestHandlerInterface}.
3548
*/

src/MiddlewareFactoryInterface.php

+7-7
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,17 @@
66

77
use Psr\Http\Server\MiddlewareInterface;
88

9+
/**
10+
* Creates a PSR-15 middleware based on the definition provided.
11+
* You may implement this interface if you want to introduce custom definitions or pass additional data to
12+
* the middleware created.
13+
*/
914
interface MiddlewareFactoryInterface
1015
{
1116
/**
12-
* @param array|callable|string $middlewareDefinition A name of PSR-15 middleware, a callable with
13-
* `function(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface` signature or
14-
* a handler action (an array of [handlerClass, handlerMethod]). For handler action and callable typed parameters
15-
* are automatically injected using dependency injection container passed to the route.
16-
* Current request and handler could be obtained by type-hinting for {@see ServerRequestInterface}
17-
* and {@see RequestHandlerInterface}.
17+
* Create a PSR-15 middleware based on definition provided.
1818
*
19-
* @return MiddlewareInterface
19+
* @param array|callable|string $middlewareDefinition Middleware definition to use.
2020
*/
2121
public function create($middlewareDefinition): MiddlewareInterface;
2222
}

src/MiddlewareStack.php

+11-1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ final class MiddlewareStack implements MiddlewarePipelineInterface
2525

2626
private EventDispatcherInterface $eventDispatcher;
2727

28+
/**
29+
* @param EventDispatcherInterface $eventDispatcher Event dispatcher to use for triggering before/after middleware
30+
* events.
31+
*/
2832
public function __construct(EventDispatcherInterface $eventDispatcher)
2933
{
3034
$this->eventDispatcher = $eventDispatcher;
@@ -53,18 +57,24 @@ public function handle(ServerRequestInterface $request): ResponseInterface
5357
return $this->stack->handle($request);
5458
}
5559

60+
/**
61+
* Reset the stack.
62+
*/
5663
public function reset(): void
5764
{
5865
$this->stack = null;
5966
}
6067

68+
/**
69+
* @return bool Whether stack is empty.
70+
*/
6171
public function isEmpty(): bool
6272
{
6373
return $this->stack === null;
6474
}
6575

6676
/**
67-
* Wraps handler by middlewares
77+
* Wrap handler by middlewares.
6878
*/
6979
private function wrap(MiddlewareInterface $middleware, RequestHandlerInterface $handler): RequestHandlerInterface
7080
{

0 commit comments

Comments
 (0)