Passed
Push — master ( a154a4...db1aba )
by Mihail
11:52
created

HTTPError::getStatusCode()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Koded\Framework;
4
5
use Koded\Http\Interfaces\HttpStatus;
6
use Koded\Http\StatusCode;
7
use RuntimeException;
8
use Throwable;
9
use function array_filter;
10
use function Koded\Stdlib\{json_serialize, xml_serialize};
0 ignored issues
show
Bug introduced by
The type Koded\Stdlib\json_serialize was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
Bug introduced by
The type Koded\Stdlib\xml_serialize was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
11
use function rawurldecode;
12
13
14
interface KodedHTTPError
15
{
16
    public function getStatusCode(): int;
17
18
    public function getTitle(): string;
19
20
    public function getType(): string;
21
22
    public function getDetail(): string;
23
24
    public function getInstance(): string;
25
26
    public function getHeaders(): iterable;
27
28
    public function setMember(string $name, mixed $value): static;
29
30
    public function toJson(): string;
31
32
    public function toXml(): string;
33
34
    public function toArray(): array;
35
}
36
37
/**
38
 * Represents a generic HTTP error.
39
 * Follows the RFC-7807 (https://tools.ietf.org/html/rfc7807)
40
 *
41
 * Raise an instance of subclass of `HTTPError` to have Koded return
42
 * a formatted error response and appropriate HTTP status code to
43
 * the client when something goes wrong. JSON and XML media types are
44
 * supported by default.
45
 *
46
 * NOTE:
47
 *  if you wish to return custom error messages, you can create
48
 *  your own HTTPError subclass and register it with the error
49
 *  handler method to convert it into the desired HTTP response.
50
 *
51
 * @link https://tools.ietf.org/html/rfc7807
52
 */
53
class HTTPError extends RuntimeException implements KodedHTTPError
54
{
55
    /**
56
     * Extension members for problem type definitions may extend the
57
     * problem details object with additional information. Clients
58
     * consuming problem MUST ignore any extensions that they don't
59
     * recognize, allowing problem types to evolve and include
60
     * additional information in the future.
61
     *
62
     * @var array
63
     */
64
    protected array $members = [];
65
66
    /**
67
     * HTTPError constructor.
68
     *
69
     * @param int             $status   HTTP status code
70
     * @param string          $title    Error title to send to the client. If not provided, defaults to status line
71
     * @param string          $detail   Human-friendly description of the error, along with a helpful suggestion or two
72
     * @param string          $instance A URI reference that identifies the specific occurrence of the problem.
73
     * @param string          $type     A URI reference that identifies the problem type and points to a human-readable documentation
74
     * @param array|null      $headers  Extra headers to add to the response
75
     * @param Throwable|null $previous The previous Throwable, if any
76
     */
77 11
    public function __construct(
78
        int              $status,
79
        protected string $title = '',
80
        protected string $detail = '',
81
        protected string $instance = '',
82
        protected string $type = '',
83
        protected ?array $headers = [],
84
        ?Throwable       $previous = null)
85
    {
86 11
        $this->code = $status ?: HttpStatus::I_AM_TEAPOT;
87 11
        $this->message = $title ?: HttpStatus::CODE[$this->code];
88
        [
89 11
            'title'    => $this->title,
90 11
            'type'     => $this->type,
91 11
            'detail'   => $this->detail,
92 11
            'instance' => $this->instance
93 11
        ] = $this->toArray();
94 11
        parent::__construct($this->message, $this->code, $previous);
95 11
    }
96
97 1
    public function getStatusCode(): int
98
    {
99 1
        return $this->code;
100
    }
101
102 4
    public function getTitle(): string
103
    {
104 4
        return $this->title;
105
    }
106
107
    public function getType(): string
108
    {
109
        return $this->type;
110
    }
111
112 7
    public function getDetail(): string
113
    {
114 7
        return $this->detail;
115
    }
116
117 2
    public function getInstance(): string
118
    {
119 2
        return $this->instance;
120
    }
121
122 2
    public function getHeaders(): iterable
123
    {
124 2
        return $this->headers ?? [];
125
    }
126
127 6
    public function setMember(string $name, mixed $value): static
128
    {
129 6
        $this->members[$name] = $value;
130 6
        return $this;
131
    }
132
133 2
    public function toJson(): string
134
    {
135 2
        return rawurldecode(json_serialize(array_filter($this->toArray())));
136
    }
137
138
    public function toXml(): string
139
    {
140
        return rawurldecode(xml_serialize('problem', array_filter($this->toArray())));
141
    }
142
143
    /**
144
     * @return array{status: int, instance: string, detail: string, title: string, type: string}
145
     */
146 11
    public function toArray(): array
147
    {
148 11
        $status = ($this->code < 100 || $this->code > 599)
149
            ? HttpStatus::I_AM_TEAPOT
150 11
            : $this->code;
151
152 11
        return \array_merge([
153 11
            'status'   => $status,
154 11
            'instance' => $this->instance,
155 11
            'detail'   => $this->detail ?: StatusCode::description($status),
156 11
            'title'    => $this->title ?: $this->message,
157 11
            'type'     => $this->type ?: "https://httpstatuses.com/$status",
158 11
        ], $this->members);
159
    }
160
161 2
    public function __serialize(): array
162
    {
163 2
        return $this->toArray() + [
164 2
            'members' => $this->members,
165 2
            'headers' => $this->headers,
166
        ];
167
    }
168
169 2
    public function __unserialize(array $data): void
170
    {
171
        list(
172 2
            'status'   => $this->code,
173 2
            'title'    => $this->title,
174 2
            'title'    => $this->message,
175 2
            'type'     => $this->type,
176 2
            'detail'   => $this->detail,
177 2
            'instance' => $this->instance,
178 2
            'members'  => $this->members,
179 2
            'headers'  => $this->headers,
180
        ) = $data;
181 2
    }
182
}
183