Passed
Push — master ( a65062...b7f261 )
by Mihail
02:12
created

client_prefers()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
eloc 6
nc 3
nop 1
dl 0
loc 10
ccs 6
cts 6
cp 1
crap 4
rs 10
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
3
use Koded\Framework\HTTPError;
4
//use Koded\Framework\I18n\{I18n, I18nCatalog};
5
use Koded\Http\AcceptHeaderNegotiator;
6
use Koded\Http\Interfaces\{Request, Response};
7
use Psr\Http\Message\{ResponseInterface, ServerRequestInterface};
8
use function Koded\Http\create_stream;
9
10
11
function start_response(Request $request, Response $response): void
12
{
13
    if (false === $response->hasHeader('Content-Type')) {
14
        $media = $request->getAttribute('@media') ?? client_prefers($request);
15
        // [NOTE]: Web browsers have weird Accept headers and
16
        // this renderer overrules the default XML and/or XHTML type
17
        // by preferring JSON, hence forcing the response for ReST apps.
18
        if (str_contains($media, 'html')) {
19
            $media = 'application/json';
20
        }
21
        $response = $response
22
            ->withHeader('Content-Type', $media)
23
            ->withAddedHeader('Vary', 'Content-Type');
24
    }
25
    $response->getBody()->rewind();
26
    $response->sendHeaders();
27
    echo $response->sendBody();
28
}
29
30
/**
31
 * Content type negotiation.
32
 * Finds the closest match for Accept request header.
33
 *
34
 * @param ServerRequestInterface $request
35
 * @return string The content type that matches the Accept header.
36
 *                If catch-all is provided, defaults to application/json
37
 */
38
function client_prefers(ServerRequestInterface $request): string
39
{
40 2
    $media = (new AcceptHeaderNegotiator('*/*'))
41 2
        ->match($request->getHeaderLine('Accept') ?: '*/*')
42 2
        ->value();
43
44 2
    if ('*' === $media) {
45 1
        return 'application/json';
46
    }
47 1
    return $media . (str_contains($media, 'json') ? '' : '; charset=UTF-8');
48
}
49
50
/**
51
 * Exceptions serializer (follows the RFC-7807).
52
 *
53
 * @param ServerRequestInterface $request
54
 * @param ResponseInterface      $response
55
 * @param HTTPError              $exception
56
 * @return ResponseInterface
57
 * @see https://tools.ietf.org/html/rfc7807
58
 */
59
function default_serialize_error(
60
    ServerRequestInterface $request,
61
    ResponseInterface $response,
62
    HTTPError $exception): ResponseInterface
63
{
64 2
    $exception->setMember('instance', $request->getUri()->getPath());
65 2
    $response = $response
66 2
        ->withHeader('X-Error-Status', join(' ', [$response->getStatusCode(), $response->getReasonPhrase()]))
67 2
        ->withHeader('X-Error-Message', str_replace(["\n", "\r", "\t"], ' ', $exception->getDetail()))
68 2
        ->withHeader('Cache-Control', 'no-cache, max-age=0')
69 2
        ->withHeader('Connection', 'close');
70
71 2
    if (str_contains(client_prefers($request), 'xml')) {
72
        return $response
73
            ->withHeader('Content-Type', 'application/problem+xml')
74
            ->withBody(create_stream($exception->toXml()));
75
    }
76
    return $response
77 2
        ->withHeader('Content-Type', 'application/problem+json')
78 2
        ->withBody(create_stream($exception->toJson()));
79
}
80