Passed
Branch release (695ec7)
by Henry
04:31
created

Response::withDefaults()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 25
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 11
c 1
b 0
f 0
nc 4
nop 5
dl 0
loc 25
rs 9.6111
1
<?php
2
/**
3
 * This file is part of the Divergence package.
4
 *
5
 * (c) Henry Paradiz <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
namespace Divergence\Responders;
11
12
use GuzzleHttp\Psr7\MessageTrait;
13
use Psr\Http\Message\ResponseInterface;
14
15
/**
16
 * Default PSR7 Compatible Response Object for Divergence Framework
17
 *
18
 * Large parts of this file were copied from Guzzle's psr7 library.
19
 * I would have simply extended it but I didn't like the constructor design so I instead copied the code.
20
 *
21
 * {@inheritDoc}
22
 */
23
class Response implements ResponseInterface
24
{
25
    use MessageTrait;
26
27
    /** Map of standard HTTP status code/reason phrases */
28
    private const PHRASES = [
29
        100 => 'Continue',
30
        101 => 'Switching Protocols',
31
        102 => 'Processing',
32
        200 => 'OK',
33
        201 => 'Created',
34
        202 => 'Accepted',
35
        203 => 'Non-Authoritative Information',
36
        204 => 'No Content',
37
        205 => 'Reset Content',
38
        206 => 'Partial Content',
39
        207 => 'Multi-status',
40
        208 => 'Already Reported',
41
        300 => 'Multiple Choices',
42
        301 => 'Moved Permanently',
43
        302 => 'Found',
44
        303 => 'See Other',
45
        304 => 'Not Modified',
46
        305 => 'Use Proxy',
47
        306 => 'Switch Proxy',
48
        307 => 'Temporary Redirect',
49
        400 => 'Bad Request',
50
        401 => 'Unauthorized',
51
        402 => 'Payment Required',
52
        403 => 'Forbidden',
53
        404 => 'Not Found',
54
        405 => 'Method Not Allowed',
55
        406 => 'Not Acceptable',
56
        407 => 'Proxy Authentication Required',
57
        408 => 'Request Time-out',
58
        409 => 'Conflict',
59
        410 => 'Gone',
60
        411 => 'Length Required',
61
        412 => 'Precondition Failed',
62
        413 => 'Request Entity Too Large',
63
        414 => 'Request-URI Too Large',
64
        415 => 'Unsupported Media Type',
65
        416 => 'Requested range not satisfiable',
66
        417 => 'Expectation Failed',
67
        418 => 'I\'m a teapot',
68
        422 => 'Unprocessable Entity',
69
        423 => 'Locked',
70
        424 => 'Failed Dependency',
71
        425 => 'Unordered Collection',
72
        426 => 'Upgrade Required',
73
        428 => 'Precondition Required',
74
        429 => 'Too Many Requests',
75
        431 => 'Request Header Fields Too Large',
76
        451 => 'Unavailable For Legal Reasons',
77
        500 => 'Internal Server Error',
78
        501 => 'Not Implemented',
79
        502 => 'Bad Gateway',
80
        503 => 'Service Unavailable',
81
        504 => 'Gateway Time-out',
82
        505 => 'HTTP Version not supported',
83
        506 => 'Variant Also Negotiates',
84
        507 => 'Insufficient Storage',
85
        508 => 'Loop Detected',
86
        510 => 'Not Extended',
87
        511 => 'Network Authentication Required',
88
    ];
89
90
    /** @var string */
91
    private $reasonPhrase;
92
93
    /** @var int */
94
    private $statusCode;
95
96
    public function __construct(ResponseBuilder $responseBuilder)
97
    {
98
        $this
99
        ->withDefaults(200, [
100
            'Content-Type' => $responseBuilder->getContentType(),
101
        ], $responseBuilder->getBody());
102
    }
103
104
    /**
105
     * @param int                                  $status  Status code
106
     * @param array<string, string|string[]>       $headers Response headers
107
     * @param string|resource|StreamInterface|null $body    Response body
0 ignored issues
show
Bug introduced by
The type Divergence\Responders\StreamInterface 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...
108
     * @param string                               $version Protocol version
109
     * @param string|null                          $reason  Reason phrase (when empty a default will be used based on the status code)
110
     * @return static
111
     */
112
    public function withDefaults(
113
        int $status = 200,
114
        array $headers = [],
115
        $body = null,
116
        string $version = '1.1',
117
        string $reason = null
118
    ) {
119
        $this->assertStatusCodeRange($status);
120
121
        $this->statusCode = $status;
122
123
        if ($body !== '' && $body !== null) {
124
            $this->stream = \GuzzleHttp\Psr7\stream_for($body);
125
        }
126
127
        $this->setHeaders($headers);
128
        if ($reason == '' && isset(self::PHRASES[$this->statusCode])) {
129
            $this->reasonPhrase = self::PHRASES[$this->statusCode];
130
        } else {
131
            $this->reasonPhrase = (string) $reason;
132
        }
133
134
        $this->protocol = $version;
135
136
        return $this;
137
    }
138
139
    public function getStatusCode(): int
140
    {
141
        return $this->statusCode;
142
    }
143
144
    public function getReasonPhrase(): string
145
    {
146
        return $this->reasonPhrase;
147
    }
148
149
    public function withStatus($code, $reasonPhrase = ''): ResponseInterface
150
    {
151
        $this->assertStatusCodeIsInteger($code);
152
        $code = (int) $code;
153
        $this->assertStatusCodeRange($code);
154
155
        $new = clone $this;
156
        $new->statusCode = $code;
157
        if ($reasonPhrase == '' && isset(self::PHRASES[$new->statusCode])) {
158
            $reasonPhrase = self::PHRASES[$new->statusCode];
159
        }
160
        $new->reasonPhrase = (string) $reasonPhrase;
161
        return $new;
162
    }
163
164
    /**
165
     * @param mixed $statusCode
166
     */
167
    private function assertStatusCodeIsInteger($statusCode): void
168
    {
169
        if (filter_var($statusCode, FILTER_VALIDATE_INT) === false) {
170
            throw new \InvalidArgumentException('Status code must be an integer value.');
171
        }
172
    }
173
174
    private function assertStatusCodeRange(int $statusCode): void
175
    {
176
        if ($statusCode < 100 || $statusCode >= 600) {
177
            throw new \InvalidArgumentException('Status code must be an integer value between 1xx and 5xx.');
178
        }
179
    }
180
}
181