Code Coverage |
||||||||||||||||
Lines |
Branches |
Paths |
Functions and Methods |
Classes and Traits |
||||||||||||
| Total | |
100.00% |
103 / 103 |
|
96.34% |
79 / 82 |
|
64.29% |
45 / 70 |
|
93.94% |
31 / 33 |
CRAP | |
0.00% |
0 / 1 |
| Request | |
100.00% |
103 / 103 |
|
96.34% |
79 / 82 |
|
64.29% |
45 / 70 |
|
100.00% |
33 / 33 |
192.80 | |
100.00% |
1 / 1 |
| __construct | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| unwrap | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| wrap | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| params | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| param | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| form | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
2 | |||
| field | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
2 | |||
| cookies | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| cookie | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| serverParams | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| server | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| header | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| headerArray | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| headers | |
100.00% |
7 / 7 |
|
100.00% |
3 / 3 |
|
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
2 | |||
| setHeader | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| addHeader | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| removeHeader | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| hasHeader | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| attributes | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| set | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| get | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| uri | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| origin | |
100.00% |
6 / 6 |
|
71.43% |
5 / 7 |
|
25.00% |
1 / 4 |
|
100.00% |
1 / 1 |
6.80 | |||
| target | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| method | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| isMethod | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| body | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| json | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| files | |
100.00% |
11 / 11 |
|
100.00% |
13 / 13 |
|
36.36% |
4 / 11 |
|
100.00% |
1 / 1 |
15.28 | |||
| file | |
100.00% |
17 / 17 |
|
100.00% |
13 / 13 |
|
57.14% |
4 / 7 |
|
100.00% |
1 / 1 |
8.83 | |||
| returnOrFail | |
100.00% |
5 / 5 |
|
100.00% |
9 / 9 |
|
25.00% |
3 / 12 |
|
100.00% |
1 / 1 |
15.55 | |||
| formatKeys | |
100.00% |
4 / 4 |
|
75.00% |
3 / 4 |
|
50.00% |
1 / 2 |
|
100.00% |
1 / 1 |
1.12 | |||
| validateKeys | |
100.00% |
5 / 5 |
|
100.00% |
7 / 7 |
|
66.67% |
4 / 6 |
|
100.00% |
1 / 1 |
4.59 | |||
| 1 | <?php |
| 2 | |
| 3 | declare(strict_types=1); |
| 4 | |
| 5 | namespace Celemas\Core; |
| 6 | |
| 7 | use Celemas\Core\Exception\OutOfBoundsException; |
| 8 | use Celemas\Core\Exception\RuntimeException; |
| 9 | use Celemas\Router\RequestWrapper; |
| 10 | use Override; |
| 11 | use Psr\Http\Message\ServerRequestInterface as PsrServerRequest; |
| 12 | use Psr\Http\Message\StreamInterface as PsrStream; |
| 13 | use Psr\Http\Message\UploadedFileInterface as PsrUploadedFile; |
| 14 | use Psr\Http\Message\UriInterface as PsrUri; |
| 15 | |
| 16 | /** @api */ |
| 17 | class Request implements RequestWrapper |
| 18 | { |
| 19 | public function __construct( |
| 20 | protected PsrServerRequest $psrRequest, |
| 21 | ) {} |
| 22 | |
| 23 | #[Override] |
| 24 | public function unwrap(): PsrServerRequest |
| 25 | { |
| 26 | return $this->psrRequest; |
| 27 | } |
| 28 | |
| 29 | public function wrap(PsrServerRequest $request): static |
| 30 | { |
| 31 | $this->psrRequest = $request; |
| 32 | |
| 33 | return $this; |
| 34 | } |
| 35 | |
| 36 | public function params(): array |
| 37 | { |
| 38 | return $this->psrRequest->getQueryParams(); |
| 39 | } |
| 40 | |
| 41 | public function param(string $key, mixed $default = null): mixed |
| 42 | { |
| 43 | $params = $this->psrRequest->getQueryParams(); |
| 44 | $error = 'Query string variable not found'; |
| 45 | |
| 46 | return $this->returnOrFail($params, $key, $default, $error, func_num_args()); |
| 47 | } |
| 48 | |
| 49 | public function form(): ?array |
| 50 | { |
| 51 | $body = $this->psrRequest->getParsedBody(); |
| 52 | assert($body === null || is_array($body), 'Parsed form body must be null or an array'); |
| 53 | |
| 54 | return $body; |
| 55 | } |
| 56 | |
| 57 | public function field(string $key, mixed $default = null): mixed |
| 58 | { |
| 59 | $body = $this->psrRequest->getParsedBody(); |
| 60 | assert($body === null || is_array($body), 'Parsed form body must be null or an array'); |
| 61 | $error = 'Form field not found'; |
| 62 | |
| 63 | return $this->returnOrFail($body, $key, $default, $error, func_num_args()); |
| 64 | } |
| 65 | |
| 66 | public function cookies(): array |
| 67 | { |
| 68 | return $this->psrRequest->getCookieParams(); |
| 69 | } |
| 70 | |
| 71 | public function cookie(string $key, mixed $default = null): mixed |
| 72 | { |
| 73 | $params = $this->psrRequest->getCookieParams(); |
| 74 | $error = 'Cookie not found'; |
| 75 | |
| 76 | return $this->returnOrFail($params, $key, $default, $error, func_num_args()); |
| 77 | } |
| 78 | |
| 79 | public function serverParams(): array |
| 80 | { |
| 81 | return $this->psrRequest->getServerParams(); |
| 82 | } |
| 83 | |
| 84 | public function server(string $key, mixed $default = null): mixed |
| 85 | { |
| 86 | $params = $this->psrRequest->getServerParams(); |
| 87 | $error = 'Server parameter not found'; |
| 88 | |
| 89 | return $this->returnOrFail($params, $key, $default, $error, func_num_args()); |
| 90 | } |
| 91 | |
| 92 | public function header(string $name): string |
| 93 | { |
| 94 | return $this->psrRequest->getHeaderLine($name); |
| 95 | } |
| 96 | |
| 97 | public function headerArray(string $header): array |
| 98 | { |
| 99 | return $this->psrRequest->getHeader($header); |
| 100 | } |
| 101 | |
| 102 | public function headers(bool $firstOnly = false): array |
| 103 | { |
| 104 | $headers = $this->psrRequest->getHeaders(); |
| 105 | |
| 106 | if ($firstOnly) { |
| 107 | return array_combine( |
| 108 | array_keys($headers), |
| 109 | array_map(static fn(array $val): string => $val[0], $headers), |
| 110 | ); |
| 111 | } |
| 112 | |
| 113 | return $headers; |
| 114 | } |
| 115 | |
| 116 | public function setHeader(string $header, string $value): static |
| 117 | { |
| 118 | $this->psrRequest = $this->psrRequest->withHeader($header, $value); |
| 119 | |
| 120 | return $this; |
| 121 | } |
| 122 | |
| 123 | public function addHeader(string $header, string $value): static |
| 124 | { |
| 125 | $this->psrRequest = $this->psrRequest->withAddedHeader($header, $value); |
| 126 | |
| 127 | return $this; |
| 128 | } |
| 129 | |
| 130 | public function removeHeader(string $header): static |
| 131 | { |
| 132 | $this->psrRequest = $this->psrRequest->withoutHeader($header); |
| 133 | |
| 134 | return $this; |
| 135 | } |
| 136 | |
| 137 | public function hasHeader(string $header): bool |
| 138 | { |
| 139 | return $this->psrRequest->hasHeader($header); |
| 140 | } |
| 141 | |
| 142 | public function attributes(): array |
| 143 | { |
| 144 | return $this->psrRequest->getAttributes(); |
| 145 | } |
| 146 | |
| 147 | public function set(string $attribute, mixed $value): static |
| 148 | { |
| 149 | $this->psrRequest = $this->psrRequest->withAttribute($attribute, $value); |
| 150 | |
| 151 | return $this; |
| 152 | } |
| 153 | |
| 154 | public function get(string $key, mixed $default = null): mixed |
| 155 | { |
| 156 | $params = $this->psrRequest->getAttributes(); |
| 157 | $error = 'Request attribute not found'; |
| 158 | |
| 159 | return $this->returnOrFail($params, $key, $default, $error, func_num_args()); |
| 160 | } |
| 161 | |
| 162 | public function uri(): PsrUri |
| 163 | { |
| 164 | return $this->psrRequest->getUri(); |
| 165 | } |
| 166 | |
| 167 | public function origin(): string |
| 168 | { |
| 169 | $uri = $this->psrRequest->getUri(); |
| 170 | $scheme = $uri->getScheme(); |
| 171 | $origin = $scheme ? $scheme . ':' : ''; |
| 172 | $authority = $uri->getAuthority(); |
| 173 | $origin .= $authority ? '//' . $authority : ''; |
| 174 | |
| 175 | return $origin; |
| 176 | } |
| 177 | |
| 178 | public function target(): string |
| 179 | { |
| 180 | return $this->psrRequest->getRequestTarget(); |
| 181 | } |
| 182 | |
| 183 | public function method(): string |
| 184 | { |
| 185 | return strtoupper($this->psrRequest->getMethod()); |
| 186 | } |
| 187 | |
| 188 | public function isMethod(string $method): bool |
| 189 | { |
| 190 | return strtoupper($method) === $this->method(); |
| 191 | } |
| 192 | |
| 193 | public function body(): PsrStream |
| 194 | { |
| 195 | return $this->psrRequest->getBody(); |
| 196 | } |
| 197 | |
| 198 | public function json( |
| 199 | int $flags = JSON_OBJECT_AS_ARRAY, |
| 200 | ): mixed { |
| 201 | $body = (string) $this->psrRequest->getBody(); |
| 202 | |
| 203 | return json_decode( |
| 204 | $body, |
| 205 | true, |
| 206 | 512, // PHP default value |
| 207 | $flags, |
| 208 | ); |
| 209 | } |
| 210 | |
| 211 | /** |
| 212 | * Returns always a list of uploaded files, even if there is |
| 213 | * only one file. |
| 214 | * |
| 215 | * Psalm does not support multi file uploads yet and complains |
| 216 | * about type issues. We need to suppres some of these errors. |
| 217 | * |
| 218 | * @no-named-arguments |
| 219 | * |
| 220 | * @param list<string>|string ...$keys |
| 221 | * |
| 222 | * @throws OutOfBoundsException RuntimeException |
| 223 | */ |
| 224 | public function files(array|string ...$keys): array |
| 225 | { |
| 226 | $files = $this->psrRequest->getUploadedFiles(); |
| 227 | $keys = $this->validateKeys($keys); |
| 228 | |
| 229 | if (count($keys) === 0) { |
| 230 | return $files; |
| 231 | } |
| 232 | |
| 233 | // Walk into the uploaded files structure |
| 234 | foreach ($keys as $key) { |
| 235 | if (is_array($files) && array_key_exists($key, $files)) { |
| 236 | /** |
| 237 | * @psalm-suppress MixedAssignment |
| 238 | * |
| 239 | * Psalm does not support recursive types like: |
| 240 | * T = array<string, string|T> |
| 241 | */ |
| 242 | $files = $files[$key]; |
| 243 | } else { |
| 244 | throw new OutOfBoundsException('Invalid files key ' . $this->formatKeys($keys)); |
| 245 | } |
| 246 | } |
| 247 | |
| 248 | // Check if it is a single file upload. |
| 249 | // A multifile upload would already produce an array |
| 250 | if ($files instanceof PsrUploadedFile) { |
| 251 | return [$files]; |
| 252 | } |
| 253 | |
| 254 | assert(is_array($files), 'Uploaded files selection must resolve to an array'); |
| 255 | |
| 256 | return $files; |
| 257 | } |
| 258 | |
| 259 | /** |
| 260 | * Psalm does not support multi file uploads yet and complains |
| 261 | * about type issues. We need to suppres some of the errors. |
| 262 | * |
| 263 | * @no-named-arguments |
| 264 | * |
| 265 | * @param list<non-empty-string>|string ...$keys |
| 266 | * |
| 267 | * @throws OutOfBoundsException RuntimeException |
| 268 | */ |
| 269 | public function file(array|string ...$keys): PsrUploadedFile |
| 270 | { |
| 271 | $keys = $this->validateKeys($keys); |
| 272 | |
| 273 | if (count($keys) === 0) { |
| 274 | throw new RuntimeException('No file key given'); |
| 275 | } |
| 276 | |
| 277 | $files = $this->psrRequest->getUploadedFiles(); |
| 278 | $i = 0; |
| 279 | |
| 280 | foreach ($keys as $key) { |
| 281 | if (isset($files[$key])) { |
| 282 | /** @var array|PsrUploadedFile $files */ |
| 283 | $files = $files[$key]; |
| 284 | $i++; |
| 285 | |
| 286 | if ($files instanceof PsrUploadedFile) { |
| 287 | if ($i < count($keys)) { |
| 288 | throw new OutOfBoundsException( |
| 289 | 'Invalid file key (too deep) ' . $this->formatKeys($keys), |
| 290 | ); |
| 291 | } |
| 292 | |
| 293 | return $files; |
| 294 | } |
| 295 | } else { |
| 296 | throw new OutOfBoundsException('Invalid file key ' . $this->formatKeys($keys)); |
| 297 | } |
| 298 | } |
| 299 | |
| 300 | throw new RuntimeException('Multiple files available at key ' . $this->formatKeys($keys)); |
| 301 | } |
| 302 | |
| 303 | private function returnOrFail( |
| 304 | ?array $array, |
| 305 | string $key, |
| 306 | mixed $default, |
| 307 | string $error, |
| 308 | int $numArgs, |
| 309 | ): mixed { |
| 310 | if (($array === null || !array_key_exists($key, $array)) && $numArgs > 1) { |
| 311 | return $default; |
| 312 | } |
| 313 | |
| 314 | assert($array !== null, 'Input array must not be null when no default value is provided'); |
| 315 | |
| 316 | if (array_key_exists($key, $array)) { |
| 317 | return $array[$key]; |
| 318 | } |
| 319 | |
| 320 | throw new OutOfBoundsException("{$error}: '{$key}'"); |
| 321 | } |
| 322 | |
| 323 | /** @param non-empty-list<string> $keys */ |
| 324 | private function formatKeys(array $keys): string |
| 325 | { |
| 326 | return implode('', array_map( |
| 327 | static fn($key) => "['" . $key . "']", |
| 328 | $keys, |
| 329 | )); |
| 330 | } |
| 331 | |
| 332 | /** |
| 333 | * @param list<list<string>|string> $keys |
| 334 | * |
| 335 | * @return list<string> |
| 336 | */ |
| 337 | private function validateKeys(array $keys): array |
| 338 | { |
| 339 | if (isset($keys[0]) && is_array($keys[0])) { |
| 340 | if (count($keys) > 1) { |
| 341 | throw new RuntimeException('Either provide a single array or plain string arguments'); |
| 342 | } |
| 343 | $keys = $keys[0]; |
| 344 | } |
| 345 | |
| 346 | /** @var list<string> $keys */ |
| 347 | return $keys; |
| 348 | } |
| 349 | } |
Below are the source code lines that represent each code branch as identified by Xdebug. Please note a branch is not
necessarily coterminous with a line, a line may contain multiple branches and therefore show up more than once.
Please also be aware that some branches may be implicit rather than explicit, e.g. an if statement
always has an else as part of its logical flow even if you didn't write one.
| 20 | protected PsrServerRequest $psrRequest, |
| 21 | ) {} |
| 123 | public function addHeader(string $header, string $value): static |
| 124 | { |
| 125 | $this->psrRequest = $this->psrRequest->withAddedHeader($header, $value); |
| 126 | |
| 127 | return $this; |
| 128 | } |
| 144 | return $this->psrRequest->getAttributes(); |
| 145 | } |
| 195 | return $this->psrRequest->getBody(); |
| 196 | } |
| 71 | public function cookie(string $key, mixed $default = null): mixed |
| 72 | { |
| 73 | $params = $this->psrRequest->getCookieParams(); |
| 74 | $error = 'Cookie not found'; |
| 75 | |
| 76 | return $this->returnOrFail($params, $key, $default, $error, func_num_args()); |
| 77 | } |
| 68 | return $this->psrRequest->getCookieParams(); |
| 69 | } |
| 57 | public function field(string $key, mixed $default = null): mixed |
| 58 | { |
| 59 | $body = $this->psrRequest->getParsedBody(); |
| 60 | assert($body === null || is_array($body), 'Parsed form body must be null or an array'); |
| 61 | $error = 'Form field not found'; |
| 62 | |
| 63 | return $this->returnOrFail($body, $key, $default, $error, func_num_args()); |
| 64 | } |
| 269 | public function file(array|string ...$keys): PsrUploadedFile |
| 270 | { |
| 271 | $keys = $this->validateKeys($keys); |
| 272 | |
| 273 | if (count($keys) === 0) { |
| 274 | throw new RuntimeException('No file key given'); |
| 277 | $files = $this->psrRequest->getUploadedFiles(); |
| 278 | $i = 0; |
| 279 | |
| 280 | foreach ($keys as $key) { |
| 280 | foreach ($keys as $key) { |
| 281 | if (isset($files[$key])) { |
| 283 | $files = $files[$key]; |
| 284 | $i++; |
| 285 | |
| 286 | if ($files instanceof PsrUploadedFile) { |
| 287 | if ($i < count($keys)) { |
| 288 | throw new OutOfBoundsException( |
| 289 | 'Invalid file key (too deep) ' . $this->formatKeys($keys), |
| 293 | return $files; |
| 281 | if (isset($files[$key])) { |
| 296 | throw new OutOfBoundsException('Invalid file key ' . $this->formatKeys($keys)); |
| 280 | foreach ($keys as $key) { |
| 280 | foreach ($keys as $key) { |
| 281 | if (isset($files[$key])) { |
| 282 | /** @var array|PsrUploadedFile $files */ |
| 283 | $files = $files[$key]; |
| 284 | $i++; |
| 285 | |
| 286 | if ($files instanceof PsrUploadedFile) { |
| 287 | if ($i < count($keys)) { |
| 288 | throw new OutOfBoundsException( |
| 289 | 'Invalid file key (too deep) ' . $this->formatKeys($keys), |
| 290 | ); |
| 291 | } |
| 292 | |
| 293 | return $files; |
| 294 | } |
| 295 | } else { |
| 296 | throw new OutOfBoundsException('Invalid file key ' . $this->formatKeys($keys)); |
| 297 | } |
| 298 | } |
| 299 | |
| 300 | throw new RuntimeException('Multiple files available at key ' . $this->formatKeys($keys)); |
| 301 | } |
| 224 | public function files(array|string ...$keys): array |
| 225 | { |
| 226 | $files = $this->psrRequest->getUploadedFiles(); |
| 227 | $keys = $this->validateKeys($keys); |
| 228 | |
| 229 | if (count($keys) === 0) { |
| 230 | return $files; |
| 234 | foreach ($keys as $key) { |
| 234 | foreach ($keys as $key) { |
| 235 | if (is_array($files) && array_key_exists($key, $files)) { |
| 235 | if (is_array($files) && array_key_exists($key, $files)) { |
| 235 | if (is_array($files) && array_key_exists($key, $files)) { |
| 235 | if (is_array($files) && array_key_exists($key, $files)) { |
| 236 | /** |
| 237 | * @psalm-suppress MixedAssignment |
| 238 | * |
| 239 | * Psalm does not support recursive types like: |
| 240 | * T = array<string, string|T> |
| 241 | */ |
| 242 | $files = $files[$key]; |
| 244 | throw new OutOfBoundsException('Invalid files key ' . $this->formatKeys($keys)); |
| 234 | foreach ($keys as $key) { |
| 234 | foreach ($keys as $key) { |
| 235 | if (is_array($files) && array_key_exists($key, $files)) { |
| 236 | /** |
| 237 | * @psalm-suppress MixedAssignment |
| 238 | * |
| 239 | * Psalm does not support recursive types like: |
| 240 | * T = array<string, string|T> |
| 241 | */ |
| 242 | $files = $files[$key]; |
| 243 | } else { |
| 244 | throw new OutOfBoundsException('Invalid files key ' . $this->formatKeys($keys)); |
| 245 | } |
| 246 | } |
| 247 | |
| 248 | // Check if it is a single file upload. |
| 249 | // A multifile upload would already produce an array |
| 250 | if ($files instanceof PsrUploadedFile) { |
| 251 | return [$files]; |
| 254 | assert(is_array($files), 'Uploaded files selection must resolve to an array'); |
| 255 | |
| 256 | return $files; |
| 257 | } |
| 51 | $body = $this->psrRequest->getParsedBody(); |
| 52 | assert($body === null || is_array($body), 'Parsed form body must be null or an array'); |
| 53 | |
| 54 | return $body; |
| 55 | } |
| 324 | private function formatKeys(array $keys): string |
| 325 | { |
| 326 | return implode('', array_map( |
| 326 | return implode('', array_map( |
| 326 | return implode('', array_map( |
| 327 | static fn($key) => "['" . $key . "']", |
| 327 | static fn($key) => "['" . $key . "']", |
| 328 | $keys, |
| 329 | )); |
| 330 | } |
| 154 | public function get(string $key, mixed $default = null): mixed |
| 155 | { |
| 156 | $params = $this->psrRequest->getAttributes(); |
| 157 | $error = 'Request attribute not found'; |
| 158 | |
| 159 | return $this->returnOrFail($params, $key, $default, $error, func_num_args()); |
| 160 | } |
| 137 | public function hasHeader(string $header): bool |
| 138 | { |
| 139 | return $this->psrRequest->hasHeader($header); |
| 140 | } |
| 92 | public function header(string $name): string |
| 93 | { |
| 94 | return $this->psrRequest->getHeaderLine($name); |
| 95 | } |
| 97 | public function headerArray(string $header): array |
| 98 | { |
| 99 | return $this->psrRequest->getHeader($header); |
| 100 | } |
| 102 | public function headers(bool $firstOnly = false): array |
| 103 | { |
| 104 | $headers = $this->psrRequest->getHeaders(); |
| 105 | |
| 106 | if ($firstOnly) { |
| 107 | return array_combine( |
| 108 | array_keys($headers), |
| 109 | array_map(static fn(array $val): string => $val[0], $headers), |
| 113 | return $headers; |
| 114 | } |
| 188 | public function isMethod(string $method): bool |
| 189 | { |
| 190 | return strtoupper($method) === $this->method(); |
| 191 | } |
| 199 | int $flags = JSON_OBJECT_AS_ARRAY, |
| 200 | ): mixed { |
| 201 | $body = (string) $this->psrRequest->getBody(); |
| 202 | |
| 203 | return json_decode( |
| 204 | $body, |
| 205 | true, |
| 206 | 512, // PHP default value |
| 207 | $flags, |
| 208 | ); |
| 209 | } |
| 185 | return strtoupper($this->psrRequest->getMethod()); |
| 186 | } |
| 169 | $uri = $this->psrRequest->getUri(); |
| 170 | $scheme = $uri->getScheme(); |
| 171 | $origin = $scheme ? $scheme . ':' : ''; |
| 171 | $origin = $scheme ? $scheme . ':' : ''; |
| 171 | $origin = $scheme ? $scheme . ':' : ''; |
| 171 | $origin = $scheme ? $scheme . ':' : ''; |
| 172 | $authority = $uri->getAuthority(); |
| 173 | $origin .= $authority ? '//' . $authority : ''; |
| 173 | $origin .= $authority ? '//' . $authority : ''; |
| 173 | $origin .= $authority ? '//' . $authority : ''; |
| 173 | $origin .= $authority ? '//' . $authority : ''; |
| 174 | |
| 175 | return $origin; |
| 176 | } |
| 41 | public function param(string $key, mixed $default = null): mixed |
| 42 | { |
| 43 | $params = $this->psrRequest->getQueryParams(); |
| 44 | $error = 'Query string variable not found'; |
| 45 | |
| 46 | return $this->returnOrFail($params, $key, $default, $error, func_num_args()); |
| 47 | } |
| 38 | return $this->psrRequest->getQueryParams(); |
| 39 | } |
| 130 | public function removeHeader(string $header): static |
| 131 | { |
| 132 | $this->psrRequest = $this->psrRequest->withoutHeader($header); |
| 133 | |
| 134 | return $this; |
| 135 | } |
| 304 | ?array $array, |
| 305 | string $key, |
| 306 | mixed $default, |
| 307 | string $error, |
| 308 | int $numArgs, |
| 309 | ): mixed { |
| 310 | if (($array === null || !array_key_exists($key, $array)) && $numArgs > 1) { |
| 310 | if (($array === null || !array_key_exists($key, $array)) && $numArgs > 1) { |
| 310 | if (($array === null || !array_key_exists($key, $array)) && $numArgs > 1) { |
| 310 | if (($array === null || !array_key_exists($key, $array)) && $numArgs > 1) { |
| 310 | if (($array === null || !array_key_exists($key, $array)) && $numArgs > 1) { |
| 311 | return $default; |
| 314 | assert($array !== null, 'Input array must not be null when no default value is provided'); |
| 315 | |
| 316 | if (array_key_exists($key, $array)) { |
| 317 | return $array[$key]; |
| 320 | throw new OutOfBoundsException("{$error}: '{$key}'"); |
| 321 | } |
| 84 | public function server(string $key, mixed $default = null): mixed |
| 85 | { |
| 86 | $params = $this->psrRequest->getServerParams(); |
| 87 | $error = 'Server parameter not found'; |
| 88 | |
| 89 | return $this->returnOrFail($params, $key, $default, $error, func_num_args()); |
| 90 | } |
| 81 | return $this->psrRequest->getServerParams(); |
| 82 | } |
| 147 | public function set(string $attribute, mixed $value): static |
| 148 | { |
| 149 | $this->psrRequest = $this->psrRequest->withAttribute($attribute, $value); |
| 150 | |
| 151 | return $this; |
| 152 | } |
| 116 | public function setHeader(string $header, string $value): static |
| 117 | { |
| 118 | $this->psrRequest = $this->psrRequest->withHeader($header, $value); |
| 119 | |
| 120 | return $this; |
| 121 | } |
| 180 | return $this->psrRequest->getRequestTarget(); |
| 181 | } |
| 26 | return $this->psrRequest; |
| 27 | } |
| 164 | return $this->psrRequest->getUri(); |
| 165 | } |
| 337 | private function validateKeys(array $keys): array |
| 338 | { |
| 339 | if (isset($keys[0]) && is_array($keys[0])) { |
| 339 | if (isset($keys[0]) && is_array($keys[0])) { |
| 339 | if (isset($keys[0]) && is_array($keys[0])) { |
| 340 | if (count($keys) > 1) { |
| 341 | throw new RuntimeException('Either provide a single array or plain string arguments'); |
| 343 | $keys = $keys[0]; |
| 344 | } |
| 345 | |
| 346 | /** @var list<string> $keys */ |
| 347 | return $keys; |
| 347 | return $keys; |
| 348 | } |
| 29 | public function wrap(PsrServerRequest $request): static |
| 30 | { |
| 31 | $this->psrRequest = $request; |
| 32 | |
| 33 | return $this; |
| 34 | } |
| 109 | array_map(static fn(array $val): string => $val[0], $headers), |
| 327 | static fn($key) => "['" . $key . "']", |