Header::created()   A
last analyzed

Complexity

Conditions 3
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 4
c 0
b 0
f 0
dl 0
loc 9
rs 10
cc 3
nc 2
nop 1
1
<?php
2
declare(strict_types=1);
3
4
namespace Jasny\Controller\Traits;
5
6
use Psr\Http\Message\ResponseInterface;
7
8
/**
9
 * Set HTTP response header.
10
 */
11
trait Header
12
{
13
    abstract protected function getResponse(): ResponseInterface;
14
15
    abstract protected function setResponse(ResponseInterface $response): void;
16
17
    abstract protected function getLocalReferer(): ?string;
18
19
    abstract protected function output(string $content, ?string $format = null): static;
20
21
22
    /**
23
     * Set a response header.
24
     *
25
     * @return $this
26
     */
27
    protected function header(string $header, string|int|\Stringable $value, bool $add = false): static
28
    {
29
        $response = $add
30
            ? $this->getResponse()->withAddedHeader($header, (string)$value)
31
            : $this->getResponse()->withHeader($header, (string)$value);
32
        $this->setResponse($response);
33
34
        return $this;
35
    }
36
37
    /**
38
     * Set the HTTP status code.
39
     * @link http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
40
     *
41
     * Examples:
42
     * <code>
43
     *   $this->status(200);
44
     *   $this->status("200 Ok");
45
     * </code>
46
     *
47
     * @param int|string $status
48
     * @return $this
49
     */
50
    protected function status(int|string $status): static
51
    {
52
        if (is_string($status)) {
53
            [$status, $phrase] = explode(' ', $status, 2) + [1 => ''];
54
        } else {
55
            $phrase = '';
56
        }
57
58
        $response = $this->getResponse()->withStatus((int)$status, $phrase);
59
        $this->setResponse($response);
60
61
        return $this;
62
    }
63
64
65
    /**
66
     * Response with 200 Ok
67
     *
68
     * @return $this
69
     */
70
    protected function ok(): static
71
    {
72
        return $this->status(200);
73
    }
74
75
    /**
76
     * Response with created 201 code, and optionally the created location
77
     *
78
     * @param string|null $location  Url of created resource
79
     * @return $this
80
     */
81
    protected function created(?string $location = null): static
82
    {
83
        $this->status(201);
84
85
        if ($location !== null && $location !== '') {
86
            $this->header('Location', $location);
87
        }
88
89
        return $this;
90
    }
91
92
    /**
93
     * Response with 202 Accepted
94
     */
95
    protected function accepted(): static
96
    {
97
        return $this->status(202);
98
    }
99
100
    /**
101
     * Response with 204 No Content
102
     *
103
     * @param int $status  204 (No Content) or 205 (Reset Content)
104
     */
105
    protected function noContent(int $status = 204): static
106
    {
107
        if ($status !== 204 && $status !== 205) {
108
            throw new \DomainException("Invalid status code $status for no content response");
109
        }
110
111
        return $this->status($status);
112
    }
113
114
    /**
115
     * Respond with a 206 Partial content with `Content-Range` header
116
     *
117
     * @param int $rangeFrom  Beginning of the range in bytes
118
     * @param int $rangeTo    End of the range in bytes
119
     * @param int $totalSize  Total size in bytes
120
     * @return $this
121
     */
122
    protected function partialContent(int $rangeFrom, int $rangeTo, int $totalSize): static
123
    {
124
        return $this
125
            ->status(206)
126
            ->header('Content-Range', "bytes {$rangeFrom}-{$rangeTo}/{$totalSize}")
127
            ->header('Content-Length', $rangeTo - $rangeFrom);
128
    }
129
130
131
    /**
132
     * Redirect to url and output a short message with the link
133
     *
134
     * @param string     $url
135
     * @param int|string $status  301 (Moved Permanently), 302 (Found), 303 (See Other) or 307 (Temporary Redirect)
136
     * @return $this
137
     */
138
    protected function redirect(string $url, int|string $status = 303): static
139
    {
140
        if ($status < 300 || $status >= 400) {
141
            throw new \DomainException("Invalid status code $status for redirect");
142
        }
143
144
        $urlHtml = htmlentities($url);
145
146
        return $this
147
            ->status($status)
148
            ->header('Location', $url)
149
            ->output('You are being redirected to <a href="' . $urlHtml . '">' . $urlHtml . '</a>', 'text/html');
150
    }
151
152
    /**
153
     * Redirect to previous page or to home page.
154
     *
155
     * @return $this
156
     */
157
    protected function back(): static
158
    {
159
        $referer = $this->getLocalReferer();
160
        return $this->redirect($referer !== null ? $referer : '/');
161
    }
162
163
    /**
164
     * Respond with 304 Not Modified.
165
     *
166
     * @return $this
167
     */
168
    protected function notModified(): static
169
    {
170
        return $this->status(304);
171
    }
172
173
174
    /**
175
     * Respond with 400 Bad Request
176
     *
177
     * @param int $status  HTTP status code
178
     * @return $this
179
     */
180
    protected function badRequest(int $status = 400): static
181
    {
182
        if ($status < 400 || $status >= 500) {
183
            throw new \DomainException("Invalid status code $status for bad request response");
184
        }
185
186
        return $this->status($status);
187
    }
188
189
    /**
190
     * Respond with a 401 Unauthorized
191
     *
192
     * @return $this
193
     */
194
    protected function unauthorized(): static
195
    {
196
        return $this->status(401);
197
    }
198
199
    /**
200
     * Respond with 402 Payment Required
201
     *
202
     * @return $this
203
     */
204
    protected function paymentRequired(): static
205
    {
206
        return $this->status(402);
207
    }
208
209
    /**
210
     * Respond with 403 Forbidden
211
     *
212
     * @return $this
213
     */
214
    protected function forbidden(): static
215
    {
216
        return $this->status(403);
217
    }
218
219
    /**
220
     * Respond with 404 Not Found, 405 Method not allowed or 410 Gone
221
     *
222
     * @param int $status  404 (Not Found), 405 (Method not allowed) or 410 (Gone)
223
     * @return $this
224
     */
225
    protected function notFound(int $status = 404): static
226
    {
227
        if ($status !== 404 && $status !== 405 && $status !== 410) {
228
            throw new \DomainException("Invalid status code $status for no content response");
229
        }
230
231
        return $this->status($status);
232
    }
233
234
    /**
235
     * Respond with 406 Not Acceptable
236
     *
237
     * @return $this
238
     */
239
    protected function notAcceptable(): static
240
    {
241
        return $this->status(406);
242
    }
243
244
    /**
245
     * Respond with 409 Conflict
246
     *
247
     * @return $this
248
     */
249
    protected function conflict(): static
250
    {
251
        return $this->status(409);
252
    }
253
254
    /**
255
     * Respond with 429 Too Many Requests
256
     *
257
     * @return $this
258
     */
259
    protected function tooManyRequests(): static
260
    {
261
        return $this->status(429);
262
    }
263
264
265
    /**
266
     * Respond with a server error
267
     *
268
     * @param int $status  HTTP status code
269
     * @return $this
270
     */
271
    protected function error(int $status = 500): static
272
    {
273
        if ($status < 500 || $status >= 600) {
274
            throw new \DomainException("Invalid status code $status for server error response");
275
        }
276
277
        return $this->status($status);
278
    }
279
}
280