Code Coverage
 
Lines
Branches
Paths
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
39 / 39
97.44% covered (success)
97.44%
38 / 39
50.00% covered (danger)
50.00%
14 / 28
85.71% covered (warning)
85.71%
6 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
HttpError
100.00% covered (success)
100.00%
39 / 39
97.44% covered (success)
97.44%
38 / 39
50.00% covered (danger)
50.00%
14 / 28
100.00% covered (success)
100.00%
7 / 7
76.12
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
4
 title
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 payload
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 request
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 statusCode
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getPrettyTrace
100.00% covered (success)
100.00%
20 / 20
93.33% covered (success)
93.33%
14 / 15
0.00% covered (danger)
0.00%
0 / 14
100.00% covered (success)
100.00%
1 / 1
5
 formatTraceArg
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
16 / 16
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
8
1<?php
2
3declare(strict_types=1);
4
5namespace Celemas\Core\Exception;
6
7use Celemas\Core\Request;
8use Exception;
9use Psr\Http\Message\ServerRequestInterface as PsrServerRequest;
10use Throwable;
11
12/**
13 * @api
14 *
15 * @psalm-consistent-constructor
16 */
17abstract class HttpError extends Exception implements CoreException
18{
19    /** @var int<0,599> */
20    protected const int code = 0;
21
22    /** @var string */
23    protected const string message = '';
24
25    protected ?PsrServerRequest $request;
26
27    public function __construct(
28        Request|PsrServerRequest|null $request = null,
29        protected mixed $payload = null,
30        string $message = '',
31        ?Throwable $previous = null,
32        int $code = 0,
33    ) {
34        parent::__construct($message ?: static::message, $code ?: static::code, $previous);
35
36        $this->request = $request instanceof Request ? $request->unwrap() : $request;
37    }
38
39    public function title(): string
40    {
41        return (string) $this->getCode() . ' ' . $this->getMessage();
42    }
43
44    public function payload(): mixed
45    {
46        return $this->payload;
47    }
48
49    public function request(): ?PsrServerRequest
50    {
51        return $this->request;
52    }
53
54    public function statusCode(): int
55    {
56        return $this->getCode();
57    }
58
59    public function getPrettyTrace(): string
60    {
61        $result = '';
62        $traceNumber = 0;
63
64        foreach ($this->getTrace() as $frame) {
65            $args = '';
66
67            if (isset($frame['args'])) {
68                $args = implode(', ', array_map($this->formatTraceArg(...), $frame['args']));
69            }
70
71            $result .= sprintf(
72                '<p class="trace"><span class="trace-number">#%s</span>'
73                . '<span class="trace-file">%s <span class="trace-line-number">(%s)</span></span>'
74                . "<code class=\"trace-code\">%s%s%s(%s)</code></p>\n",
75                $traceNumber,
76                $frame['file'] ?? '',
77                $frame['line'] ?? '',
78                isset($frame['class']) ? $frame['class'] : '',
79                isset($frame['type']) ? $frame['type'] : '', // "->" or "::"
80                $frame['function'] ?? '',
81                $args,
82            );
83
84            $traceNumber++;
85        }
86
87        return $result;
88    }
89
90    private function formatTraceArg(mixed $arg): string
91    {
92        if (is_string($arg)) {
93            return "'" . $arg . "'";
94        }
95
96        if (is_array($arg)) {
97            return 'Array';
98        }
99
100        if (is_null($arg)) {
101            return 'NULL';
102        }
103
104        if (is_bool($arg)) {
105            return $arg ? 'true' : 'false';
106        }
107
108        if (is_object($arg)) {
109            return get_class($arg);
110        }
111
112        if (is_resource($arg)) {
113            return get_resource_type($arg);
114        }
115
116        // int or float
117        return (string) $arg;
118    }
119}