ErrorResponseGenerator::getResponse()   B
last analyzed

Complexity

Conditions 8
Paths 6

Size

Total Lines 23
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 8

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 12
c 1
b 0
f 0
dl 0
loc 23
ccs 13
cts 13
cp 1
rs 8.4444
cc 8
nc 6
nop 3
crap 8
1
<?php
2
3
declare(strict_types=1);
4
5
namespace HttpSoft\ErrorHandler;
6
7
use HttpSoft\Response\HtmlResponse;
8
use HttpSoft\Response\JsonResponse;
9
use HttpSoft\Response\TextResponse;
10
use HttpSoft\Response\XmlResponse;
11
use Psr\Http\Message\ResponseInterface;
12
use Psr\Http\Message\ServerRequestInterface;
13
use Throwable;
14
15
use function array_key_exists;
16
use function array_keys;
17
use function explode;
18
use function preg_match;
19
use function strtolower;
20
use function trim;
21
use function uasort;
22
23
final class ErrorResponseGenerator implements ErrorResponseGeneratorInterface
24
{
25
    /**
26
     * {@inheritDoc}
27
     */
28 64
    public function generate(Throwable $error, ServerRequestInterface $request): ResponseInterface
29
    {
30 64
        $errorCode = (int) $error->getCode();
31 64
        $responseCode = self::STATUS_INTERNAL_SERVER_ERROR;
32
33 64
        if (array_key_exists($errorCode, self::ERROR_PHRASES)) {
34 47
            $responseCode = $errorCode;
35
        }
36
37 64
        $requestMimeTypes = $this->getSortedMimeTypesByRequest($request);
38 64
        return $this->getResponse($responseCode, self::ERROR_PHRASES[$responseCode], $requestMimeTypes);
39
    }
40
41
    /**
42
     * @param int $code
43
     * @param string $message
44
     * @param string[] $mimeTypes
45
     * @return ResponseInterface
46
     */
47 64
    private function getResponse(int $code, string $message, array $mimeTypes): ResponseInterface
48
    {
49 64
        foreach ($mimeTypes as $mimeType) {
50 51
            if ($mimeType === 'text/html' || $mimeType === '*/*') {
51 1
                return $this->getHtmlResponse($code, $message);
52
            }
53
54 50
            if ($mimeType === 'text/plain') {
55 46
                return new TextResponse("Error {$code} - {$message}", $code);
56
            }
57
58 5
            if ($mimeType === 'application/json') {
59 3
                return new JsonResponse(['name' => 'Error', 'code' => $code, 'message' => $message], $code);
60
            }
61
62 3
            if ($mimeType === 'application/xml' || $mimeType === 'text/xml') {
63 2
                $xml = '<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>';
64 2
                $xml .= "\n<error>\n<code>{$code}</code>\n<message>{$message}</message>\n</error>";
65 2
                return new XmlResponse($xml, $code);
66
            }
67
        }
68
69 15
        return $this->getHtmlResponse($code, $message);
70
    }
71
72
    /**
73
     * @param int $code
74
     * @param string $message
75
     * @return HtmlResponse
76
     */
77 15
    private function getHtmlResponse(int $code, string $message): HtmlResponse
78
    {
79 15
        $title = "Error {$code} - {$message}";
80 15
        $html = '<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><title>' . $title . '</title></head>';
81 15
        $html .= '<body style="padding:20px 10px"><h1 style="text-align:center">' . $title . '</h1></body></html>';
82 15
        return new HtmlResponse($html, $code);
83
    }
84
85
    /**
86
     * @param ServerRequestInterface $request
87
     * @return string[]
88
     */
89 64
    private function getSortedMimeTypesByRequest(ServerRequestInterface $request): array
90
    {
91 64
        if (!$acceptParameters = $request->getHeaderLine('accept')) {
92 14
            return [];
93
        }
94
95 51
        $mimeTypes = [];
96
97 51
        foreach (explode(',', $acceptParameters) as $acceptParameter) {
98 51
            $parts = explode(';', $acceptParameter);
99
100 51
            if (!isset($parts[0]) || isset($mimeTypes[$parts[0]]) || !($mimeType = strtolower(trim($parts[0])))) {
101 2
                continue;
102
            }
103
104 51
            if (!isset($parts[1])) {
105 47
                $mimeTypes[$mimeType] = 1.0;
106 47
                continue;
107
            }
108
109 9
            if (preg_match('/^\s*q=\s*(0(?:\.\d{1,3})?|1(?:\.0{1,3})?)\s*$/i', $parts[1], $matches)) {
110 9
                $mimeTypes[$mimeType] = (float) ($matches[1] ?? 1.0);
111
            }
112
        }
113
114 51
        uasort($mimeTypes, static fn(float $a, float $b) => ($a === $b) ? 0 : ($a > $b ? -1 : 1));
115 51
        return array_keys($mimeTypes);
116
    }
117
}
118