Passed
Push — master ( 90372d...e80252 )
by Nikolay
25:24
created

Response::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 5
c 0
b 0
f 0
rs 10
cc 1
nc 1
nop 3
1
<?php
2
/**
3
 * @see       https://github.com/zendframework/zend-diactoros for the canonical source repository
4
 * @copyright Copyright (c) 2015-2018 Zend Technologies USA Inc. (http://www.zend.com)
5
 * @license   https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License
6
 */
7
8
declare(strict_types=1);
9
10
namespace Zend\Diactoros;
11
12
use Psr\Http\Message\ResponseInterface;
13
use Psr\Http\Message\StreamInterface;
14
15
use function gettype;
16
use function is_float;
17
use function is_numeric;
18
use function is_scalar;
19
use function sprintf;
20
21
/**
22
 * HTTP response encapsulation.
23
 *
24
 * Responses are considered immutable; all methods that might change state are
25
 * implemented such that they retain the internal state of the current
26
 * message and return a new instance that contains the changed state.
27
 */
28
class Response implements ResponseInterface
29
{
30
    use MessageTrait;
31
32
    const MIN_STATUS_CODE_VALUE = 100;
33
    const MAX_STATUS_CODE_VALUE = 599;
34
35
    /**
36
     * Map of standard HTTP status code/reason phrases
37
     *
38
     * @var array
39
     */
40
    private $phrases = [
41
        // INFORMATIONAL CODES
42
        100 => 'Continue',
43
        101 => 'Switching Protocols',
44
        102 => 'Processing',
45
        103 => 'Early Hints',
46
        // SUCCESS CODES
47
        200 => 'OK',
48
        201 => 'Created',
49
        202 => 'Accepted',
50
        203 => 'Non-Authoritative Information',
51
        204 => 'No Content',
52
        205 => 'Reset Content',
53
        206 => 'Partial Content',
54
        207 => 'Multi-Status',
55
        208 => 'Already Reported',
56
        226 => 'IM Used',
57
        // REDIRECTION CODES
58
        300 => 'Multiple Choices',
59
        301 => 'Moved Permanently',
60
        302 => 'Found',
61
        303 => 'See Other',
62
        304 => 'Not Modified',
63
        305 => 'Use Proxy',
64
        306 => 'Switch Proxy', // Deprecated to 306 => '(Unused)'
65
        307 => 'Temporary Redirect',
66
        308 => 'Permanent Redirect',
67
        // CLIENT ERROR
68
        400 => 'Bad Request',
69
        401 => 'Unauthorized',
70
        402 => 'Payment Required',
71
        403 => 'Forbidden',
72
        404 => 'Not Found',
73
        405 => 'Method Not Allowed',
74
        406 => 'Not Acceptable',
75
        407 => 'Proxy Authentication Required',
76
        408 => 'Request Timeout',
77
        409 => 'Conflict',
78
        410 => 'Gone',
79
        411 => 'Length Required',
80
        412 => 'Precondition Failed',
81
        413 => 'Payload Too Large',
82
        414 => 'URI Too Long',
83
        415 => 'Unsupported Media Type',
84
        416 => 'Range Not Satisfiable',
85
        417 => 'Expectation Failed',
86
        418 => 'I\'m a teapot',
87
        421 => 'Misdirected Request',
88
        422 => 'Unprocessable Entity',
89
        423 => 'Locked',
90
        424 => 'Failed Dependency',
91
        425 => 'Too Early',
92
        426 => 'Upgrade Required',
93
        428 => 'Precondition Required',
94
        429 => 'Too Many Requests',
95
        431 => 'Request Header Fields Too Large',
96
        444 => 'Connection Closed Without Response',
97
        451 => 'Unavailable For Legal Reasons',
98
        // SERVER ERROR
99
        499 => 'Client Closed Request',
100
        500 => 'Internal Server Error',
101
        501 => 'Not Implemented',
102
        502 => 'Bad Gateway',
103
        503 => 'Service Unavailable',
104
        504 => 'Gateway Timeout',
105
        505 => 'HTTP Version Not Supported',
106
        506 => 'Variant Also Negotiates',
107
        507 => 'Insufficient Storage',
108
        508 => 'Loop Detected',
109
        510 => 'Not Extended',
110
        511 => 'Network Authentication Required',
111
        599 => 'Network Connect Timeout Error',
112
    ];
113
114
    /**
115
     * @var string
116
     */
117
    private $reasonPhrase;
118
119
    /**
120
     * @var int
121
     */
122
    private $statusCode;
123
124
    /**
125
     * @param string|resource|StreamInterface $body Stream identifier and/or actual stream resource
126
     * @param int $status Status code for the response, if any.
127
     * @param array $headers Headers for the response, if any.
128
     * @throws Exception\InvalidArgumentException on any invalid element.
129
     */
130
    public function __construct($body = 'php://memory', int $status = 200, array $headers = [])
131
    {
132
        $this->setStatusCode($status);
133
        $this->stream = $this->getStream($body, 'wb+');
134
        $this->setHeaders($headers);
135
    }
136
137
    /**
138
     * {@inheritdoc}
139
     */
140
    public function getStatusCode() : int
141
    {
142
        return $this->statusCode;
143
    }
144
145
    /**
146
     * {@inheritdoc}
147
     */
148
    public function getReasonPhrase() : string
149
    {
150
        return $this->reasonPhrase;
151
    }
152
153
    /**
154
     * {@inheritdoc}
155
     */
156
    public function withStatus($code, $reasonPhrase = '') : Response
157
    {
158
        $new = clone $this;
159
        $new->setStatusCode($code, $reasonPhrase);
160
        return $new;
161
    }
162
163
    /**
164
     * Set a valid status code.
165
     *
166
     * @param int $code
167
     * @param string $reasonPhrase
168
     * @throws Exception\InvalidArgumentException on an invalid status code.
169
     */
170
    private function setStatusCode($code, $reasonPhrase = '') : void
171
    {
172
        if (! is_numeric($code)
0 ignored issues
show
introduced by
The condition is_numeric($code) is always true.
Loading history...
173
            || is_float($code)
0 ignored issues
show
introduced by
The condition is_float($code) is always false.
Loading history...
174
            || $code < static::MIN_STATUS_CODE_VALUE
175
            || $code > static::MAX_STATUS_CODE_VALUE
176
        ) {
177
            throw new Exception\InvalidArgumentException(sprintf(
178
                'Invalid status code "%s"; must be an integer between %d and %d, inclusive',
179
                is_scalar($code) ? $code : gettype($code),
180
                static::MIN_STATUS_CODE_VALUE,
181
                static::MAX_STATUS_CODE_VALUE
182
            ));
183
        }
184
185
        if (! is_string($reasonPhrase)) {
0 ignored issues
show
introduced by
The condition is_string($reasonPhrase) is always true.
Loading history...
186
            throw new Exception\InvalidArgumentException(sprintf(
187
                'Unsupported response reason phrase; must be a string, received %s',
188
                is_object($reasonPhrase) ? get_class($reasonPhrase) : gettype($reasonPhrase)
189
            ));
190
        }
191
192
        if ($reasonPhrase === '' && isset($this->phrases[$code])) {
193
            $reasonPhrase = $this->phrases[$code];
194
        }
195
196
        $this->reasonPhrase = $reasonPhrase;
197
        $this->statusCode = (int) $code;
198
    }
199
}
200