Passed
Push — master ( e71162...5f8159 )
by Anatoly
42s queued 11s
created

Response::setStatus()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 6
nc 2
nop 2
dl 0
loc 11
ccs 7
cts 7
cp 1
crap 2
rs 10
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
3
/**
4
 * It's free open-source software released under the MIT License.
5
 *
6
 * @author Anatoly Fenric <[email protected]>
7
 * @copyright Copyright (c) 2018, Anatoly Fenric
8
 * @license https://github.com/sunrise-php/http-message/blob/master/LICENSE
9
 * @link https://github.com/sunrise-php/http-message
10
 */
11
12
namespace Sunrise\Http\Message;
13
14
/**
15
 * Import classes
16
 */
17
use Fig\Http\Message\StatusCodeInterface;
18
use Psr\Http\Message\ResponseInterface;
19
use Psr\Http\Message\StreamInterface;
20
use Sunrise\Http\Header\HeaderInterface;
21
use InvalidArgumentException;
22
23
/**
24
 * Import functions
25
 */
26
use function is_int;
27
use function is_string;
28
use function preg_match;
29
use function sprintf;
30
31
/**
32
 * HTTP Response Message
33
 *
34
 * @link https://tools.ietf.org/html/rfc7230
35
 * @link https://www.php-fig.org/psr/psr-7/
36
 */
37
class Response extends Message implements ResponseInterface, StatusCodeInterface
38
{
39
40
    /**
41
     * The response status code
42
     *
43
     * @var int
44
     */
45
    protected $statusCode = self::STATUS_OK;
46
47
    /**
48
     * The response reason phrase
49
     *
50
     * @var string
51
     */
52
    protected $reasonPhrase = REASON_PHRASES[self::STATUS_OK];
53
54
    /**
55
     * Constrictor of the class
56
     *
57
     * @param int|null $statusCode
58
     * @param string|null $reasonPhrase
59
     * @param array<string, string|array<string>>|null $headers
60
     * @param StreamInterface|null $body
61
     * @param string|null $protocolVersion
62
     *
63
     * @throws InvalidArgumentException
64
     */
65 32
    public function __construct(
66
        ?int $statusCode = null,
67
        ?string $reasonPhrase = null,
68
        ?array $headers = null,
69
        ?StreamInterface $body = null,
70
        ?string $protocolVersion = null
71
    ) {
72 32
        parent::__construct(
73 32
            $headers,
74
            $body,
75
            $protocolVersion
76
        );
77
78 32
        if (isset($statusCode)) {
79 3
            $this->setStatus($statusCode, $reasonPhrase ?? '');
80
        }
81 32
    }
82
83
    /**
84
     * {@inheritdoc}
85
     */
86 5
    public function getStatusCode() : int
87
    {
88 5
        return $this->statusCode;
89
    }
90
91
    /**
92
     * {@inheritdoc}
93
     */
94 5
    public function getReasonPhrase() : string
95
    {
96 5
        return $this->reasonPhrase;
97
    }
98
99
    /**
100
     * {@inheritdoc}
101
     *
102
     * @throws InvalidArgumentException
103
     */
104 28
    public function withStatus($statusCode, $reasonPhrase = '') : ResponseInterface
105
    {
106 28
        $clone = clone $this;
107 28
        $clone->setStatus($statusCode, $reasonPhrase);
108
109 4
        return $clone;
110
    }
111
112
    /**
113
     * Sets the given status to the response
114
     *
115
     * @param int $statusCode
116
     * @param string $reasonPhrase
117
     *
118
     * @return void
119
     *
120
     * @throws InvalidArgumentException
121
     */
122 31
    protected function setStatus($statusCode, $reasonPhrase) : void
123
    {
124 31
        $this->validateStatusCode($statusCode);
125 19
        $this->validateReasonPhrase($reasonPhrase);
126
127 7
        if ('' === $reasonPhrase) {
128 5
            $reasonPhrase = REASON_PHRASES[$statusCode] ?? 'Unknown Status Code';
129
        }
130
131 7
        $this->statusCode = $statusCode;
132 7
        $this->reasonPhrase = $reasonPhrase;
133 7
    }
134
135
    /**
136
     * Validates the given status-code
137
     *
138
     * @param mixed $statusCode
139
     *
140
     * @return void
141
     *
142
     * @throws InvalidArgumentException
143
     *
144
     * @link https://tools.ietf.org/html/rfc7230#section-3.1.2
145
     */
146 31
    protected function validateStatusCode($statusCode) : void
147
    {
148 31
        if (!is_int($statusCode)) {
149 9
            throw new InvalidArgumentException('HTTP status-code must be an integer');
150
        }
151
152 22
        if (! ($statusCode >= 100 && $statusCode <= 599)) {
153 3
            throw new InvalidArgumentException(sprintf('The status-code "%d" is not valid', $statusCode));
154
        }
155 19
    }
156
157
    /**
158
     * Validates the given reason-phrase
159
     *
160
     * @param mixed $reasonPhrase
161
     *
162
     * @return void
163
     *
164
     * @throws InvalidArgumentException
165
     *
166
     * @link https://tools.ietf.org/html/rfc7230#section-3.1.2
167
     */
168 19
    protected function validateReasonPhrase($reasonPhrase) : void
169
    {
170 19
        if (!is_string($reasonPhrase)) {
171 9
            throw new InvalidArgumentException('HTTP reason-phrase must be a string');
172
        }
173
174 10
        if (!preg_match(HeaderInterface::RFC7230_FIELD_VALUE, $reasonPhrase)) {
175 3
            throw new InvalidArgumentException(sprintf('The reason-phrase "%s" is not valid', $reasonPhrase));
176
        }
177 7
    }
178
}
179