1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace mindplay\middleman; |
4
|
|
|
|
5
|
|
|
use Interop\Http\Server\MiddlewareInterface as LegacyMiddlewareInterface; |
6
|
|
|
use InvalidArgumentException; |
7
|
|
|
use LogicException; |
8
|
|
|
use mindplay\readable; |
9
|
|
|
use Psr\Http\Message\ResponseInterface; |
10
|
|
|
use Psr\Http\Message\ServerRequestInterface; |
11
|
|
|
use Psr\Http\Server\MiddlewareInterface as PsrMiddlewareInterface; |
12
|
|
|
use Psr\Http\Server\RequestHandlerInterface; |
13
|
|
|
|
14
|
|
|
/** |
15
|
|
|
* PSR-7 / PSR-15 middleware dispatcher |
16
|
|
|
*/ |
17
|
|
|
class Dispatcher implements LegacyMiddlewareInterface, RequestHandlerInterface |
18
|
|
|
{ |
19
|
|
|
/** |
20
|
|
|
* @var callable middleware resolver |
21
|
|
|
*/ |
22
|
|
|
private $resolver; |
23
|
|
|
|
24
|
|
|
/** |
25
|
|
|
* @var mixed[] unresolved middleware stack |
26
|
|
|
*/ |
27
|
|
|
private $stack; |
28
|
|
|
|
29
|
|
|
/** |
30
|
|
|
* @param (callable|MiddlewareInterface|mixed)[] $stack middleware stack (with at least one middleware component) |
31
|
|
|
* @param callable|null $resolver optional middleware resolver: |
32
|
|
|
* function (string $name): MiddlewareInterface |
33
|
|
|
* |
34
|
|
|
* @throws InvalidArgumentException if an empty middleware stack was given |
35
|
|
|
*/ |
36
|
1 |
|
public function __construct($stack, callable $resolver = null) |
37
|
|
|
{ |
38
|
1 |
|
if (count($stack) === 0) { |
39
|
1 |
|
throw new InvalidArgumentException("an empty middleware stack was given"); |
40
|
|
|
} |
41
|
|
|
|
42
|
1 |
|
$this->stack = $stack; |
43
|
1 |
|
$this->resolver = $resolver; |
44
|
1 |
|
} |
45
|
|
|
|
46
|
|
|
/** |
47
|
|
|
* Dispatches the middleware stack and returns the resulting `ResponseInterface`. |
48
|
|
|
* |
49
|
|
|
* @param ServerRequestInterface $request |
50
|
|
|
* |
51
|
|
|
* @return ResponseInterface |
52
|
|
|
* |
53
|
|
|
* @throws LogicException on unexpected result from any middleware on the stack |
54
|
|
|
*/ |
55
|
1 |
|
public function handle(ServerRequestInterface $request): ResponseInterface |
56
|
|
|
{ |
57
|
1 |
|
$resolved = $this->resolve(0); |
58
|
|
|
|
59
|
1 |
|
return $resolved->handle($request); |
60
|
|
|
} |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* Dispatches the middleware stack and returns the resulting `ResponseInterface`. |
64
|
|
|
* |
65
|
|
|
* @deprecated in favor of identical PSR-15 method `RequestHandlerInterface::handle()` |
66
|
|
|
* |
67
|
|
|
* @param ServerRequestInterface $request |
68
|
|
|
* |
69
|
|
|
* @return ResponseInterface |
70
|
|
|
* |
71
|
|
|
* @throws LogicException on unexpected result from any middleware on the stack |
72
|
|
|
*/ |
73
|
1 |
|
public function dispatch(ServerRequestInterface $request): ResponseInterface |
74
|
|
|
{ |
75
|
1 |
|
return $this->handle($request); |
76
|
|
|
} |
77
|
|
|
|
78
|
|
|
/** |
79
|
|
|
* @inheritdoc |
80
|
|
|
*/ |
81
|
1 |
|
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface |
82
|
|
|
{ |
83
|
1 |
|
$this->stack[] = function (ServerRequestInterface $request) use ($handler) { |
84
|
1 |
|
return $handler->handle($request); |
85
|
|
|
}; |
86
|
|
|
|
87
|
1 |
|
$response = $this->dispatch($request); |
|
|
|
|
88
|
|
|
|
89
|
1 |
|
array_pop($this->stack); |
90
|
|
|
|
91
|
1 |
|
return $response; |
92
|
|
|
} |
93
|
|
|
|
94
|
|
|
/** |
95
|
|
|
* @param int $index middleware stack index |
96
|
|
|
* |
97
|
|
|
* @return RequestHandlerInterface |
98
|
|
|
*/ |
99
|
1 |
|
private function resolve($index): RequestHandlerInterface |
100
|
|
|
{ |
101
|
1 |
|
if (isset($this->stack[$index])) { |
102
|
1 |
|
return new Delegate(function (ServerRequestInterface $request) use ($index) { |
103
|
1 |
|
$middleware = $this->resolver |
104
|
1 |
|
? call_user_func($this->resolver, $this->stack[$index]) |
105
|
1 |
|
: $this->stack[$index]; // as-is |
106
|
|
|
|
107
|
|
|
switch (true) { |
108
|
1 |
|
case $middleware instanceof PsrMiddlewareInterface: |
109
|
1 |
|
case $middleware instanceof LegacyMiddlewareInterface: |
110
|
1 |
|
$result = $middleware->process($request, $this->resolve($index + 1)); |
111
|
1 |
|
break; |
112
|
|
|
|
113
|
1 |
|
case is_callable($middleware): |
114
|
1 |
|
$result = $middleware($request, $this->resolve($index + 1)); |
115
|
1 |
|
break; |
116
|
|
|
|
117
|
|
|
default: |
118
|
|
|
$given = readable::callback($middleware); |
119
|
|
|
|
120
|
|
|
throw new LogicException("unsupported middleware type: {$given}"); |
121
|
|
|
} |
122
|
|
|
|
123
|
1 |
|
if (! $result instanceof ResponseInterface) { |
124
|
1 |
|
$given = readable::value($result); |
125
|
1 |
|
$source = readable::callback($middleware); |
126
|
|
|
|
127
|
1 |
|
throw new LogicException("unexpected middleware result: {$given} returned by: {$source}"); |
128
|
|
|
} |
129
|
|
|
|
130
|
1 |
|
return $result; |
131
|
1 |
|
}); |
132
|
|
|
} |
133
|
|
|
|
134
|
1 |
|
return new Delegate(function () { |
135
|
1 |
|
throw new LogicException("unresolved request: middleware stack exhausted with no result"); |
136
|
1 |
|
}); |
137
|
|
|
} |
138
|
|
|
} |
139
|
|
|
|
This method has been deprecated. The supplier of the class has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.