Message::withHeader()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 4
c 0
b 0
f 0
dl 0
loc 7
rs 10
cc 2
nc 2
nop 2
1
<?php
2
3
/**
4
 * This file is part of slick/http
5
 *
6
 * For the full copyright and license information, please view the LICENSE
7
 * file that was distributed with this source code.
8
 */
9
10
namespace Slick\Http\Message;
11
12
use Psr\Http\Message\MessageInterface;
13
use Psr\Http\Message\StreamInterface;
14
use Slick\Http\Message\Stream\TextStream;
15
16
/**
17
 * Message
18
 *
19
 * @package Slick\Http\Message
20
*/
21
class Message implements MessageInterface
22
{
23
24
    /**
25
     * @var string
26
     */
27
    private $protocolVersion = '1.1';
28
29
    /**
30
     * @var array
31
     */
32
    protected $headers = [];
33
34
    /**
35
     * @var StreamInterface
36
     */
37
    protected $body;
38
39
    /**
40
     * Creates an HTTP Message
41
     *
42
     * @param string $body
43
     */
44
    public function __construct($body = '')
45
    {
46
        $body = $body instanceof StreamInterface
0 ignored issues
show
introduced by
$body is never a sub-type of Psr\Http\Message\StreamInterface.
Loading history...
47
            ? $body
48
            : new TextStream($body);
49
        $this->body = $body;
50
    }
51
52
    /**
53
     * Retrieves the HTTP protocol version as a string.
54
     *
55
     * The string MUST contain only the HTTP version number (e.g., "1.1", "1.0").
56
     *
57
     * @return string HTTP protocol version.
58
     */
59
    public function getProtocolVersion()
60
    {
61
        return $this->protocolVersion;
62
    }
63
64
    /**
65
     * Return an instance with the specified HTTP protocol version.
66
     *
67
     * The version string MUST contain only the HTTP version number (e.g.,
68
     * "1.1", "1.0").
69
     *
70
     * This method MUST be implemented in such a way as to retain the
71
     * immutability of the message, and MUST return an instance that has the
72
     * new protocol version.
73
     *
74
     * @param string $version HTTP protocol version
75
     * @return static
76
     */
77
    public function withProtocolVersion($version)
78
    {
79
        $message = clone $this;
80
        $message->protocolVersion = $version;
81
        return $message;
82
    }
83
84
    /**
85
     * Retrieves all message header values.
86
     *
87
     * The keys represent the header name as it will be sent over the wire, and
88
     * each value is an array of strings associated with the header.
89
     *
90
     *     // Represent the headers as a string
91
     *     foreach ($message->getHeaders() as $name => $values) {
92
     *         echo $name . ": " . implode(", ", $values);
93
     *     }
94
     *
95
     *     // Emit headers iteratively:
96
     *     foreach ($message->getHeaders() as $name => $values) {
97
     *         foreach ($values as $value) {
98
     *             header(sprintf('%s: %s', $name, $value), false);
99
     *         }
100
     *     }
101
     *
102
     * While header names are not case-sensitive, getHeaders() will preserve the
103
     * exact case in which headers were originally specified.
104
     *
105
     * @return string[][] Returns an associative array of the message's headers. Each
106
     *     key MUST be a header name, and each value MUST be an array of strings
107
     *     for that header.
108
     */
109
    public function getHeaders()
110
    {
111
        return $this->headers;
112
    }
113
114
    /**
115
     * Checks if a header exists by the given case-insensitive name.
116
     *
117
     * @param string $name Case-insensitive header field name.
118
     * @return bool Returns true if any header names match the given header
119
     *     name using a case-insensitive string comparison. Returns false if
120
     *     no matching header name is found in the message.
121
     */
122
    public function hasHeader($name)
123
    {
124
        $key = $this->headerKey($name);
125
        return array_key_exists($key, $this->headers);
126
    }
127
128
    /**
129
     * Retrieves a message header value by the given case-insensitive name.
130
     *
131
     * This method returns an array of all the header values of the given
132
     * case-insensitive header name.
133
     *
134
     * If the header does not appear in the message, this method MUST return an
135
     * empty array.
136
     *
137
     * @param string $name Case-insensitive header field name.
138
     * @return string[] An array of string values as provided for the given
139
     *    header. If the header does not appear in the message, this method MUST
140
     *    return an empty array.
141
     */
142
    public function getHeader($name)
143
    {
144
        $key = $this->headerKey($name);
145
        if (array_key_exists($key, $this->headers)) {
146
            return $this->headers[$key];
147
        }
148
149
        return [];
150
    }
151
152
    /**
153
     * Retrieves a comma-separated string of the values for a single header.
154
     *
155
     * This method returns all of the header values of the given
156
     * case-insensitive header name as a string concatenated together using
157
     * a comma.
158
     *
159
     * NOTE: Not all header values may be appropriately represented using
160
     * comma concatenation. For such headers, use getHeader() instead
161
     * and supply your own delimiter when concatenating.
162
     *
163
     * If the header does not appear in the message, this method MUST return
164
     * an empty string.
165
     *
166
     * @param string $name Case-insensitive header field name.
167
     * @return string A string of values as provided for the given header
168
     *    concatenated together using a comma. If the header does not appear in
169
     *    the message, this method MUST return an empty string.
170
     */
171
    public function getHeaderLine($name)
172
    {
173
        $header = $this->getHeader($name);
174
        return empty($header)
175
            ? ''
176
            : implode(',', $header);
177
    }
178
179
    /**
180
     * Return an instance with the provided value replacing the specified header.
181
     *
182
     * While header names are case-insensitive, the casing of the header will
183
     * be preserved by this function, and returned from getHeaders().
184
     *
185
     * This method MUST be implemented in such a way as to retain the
186
     * immutability of the message, and MUST return an instance that has the
187
     * new and/or updated header and value.
188
     *
189
     * @param string $name Case-insensitive header field name.
190
     * @param string|string[] $value Header value(s).
191
     * @return static
192
     * @throws \InvalidArgumentException for invalid header names or values.
193
     */
194
    public function withHeader($name, $value)
195
    {
196
        $key = $this->headerKey($name);
197
198
        $message = clone $this;
199
        $message->headers[$key] = is_array($value) ? $value : [$value];
200
        return $message;
201
    }
202
203
    /**
204
     * Return an instance with the specified header appended with the given value.
205
     *
206
     * Existing values for the specified header will be maintained. The new
207
     * value(s) will be appended to the existing list. If the header did not
208
     * exist previously, it will be added.
209
     *
210
     * This method MUST be implemented in such a way as to retain the
211
     * immutability of the message, and MUST return an instance that has the
212
     * new header and/or value.
213
     *
214
     * @param string $name Case-insensitive header field name to add.
215
     * @param string|string[] $value Header value(s).
216
     * @return static
217
     * @throws \InvalidArgumentException for invalid header names or values.
218
     */
219
    public function withAddedHeader($name, $value)
220
    {
221
        $header = $this->getHeader($name);
222
        $values = is_array($value) ? $value : [$value];
223
        foreach ($values as $newValue) {
224
            $header[] = $newValue;
225
        }
226
        return $this->withHeader($name, $header);
227
    }
228
229
    /**
230
     * Return an instance without the specified header.
231
     *
232
     * Header resolution MUST be done without case-sensitivity.
233
     *
234
     * This method MUST be implemented in such a way as to retain the
235
     * immutability of the message, and MUST return an instance that removes
236
     * the named header.
237
     *
238
     * @param string $name Case-insensitive header field name to remove.
239
     * @return static
240
     */
241
    public function withoutHeader($name)
242
    {
243
        $message = clone $this;
244
        $key = $this->headerKey($name);
245
246
        if (array_key_exists($key, $message->headers)) {
247
            unset($message->headers[$key]);
248
        }
249
250
        return $message;
251
    }
252
253
    /**
254
     * Gets the body of the message.
255
     *
256
     * @return StreamInterface Returns the body as a stream.
257
     */
258
    public function getBody()
259
    {
260
        return $this->body;
261
    }
262
263
    /**
264
     * Return an instance with the specified message body.
265
     *
266
     * The body MUST be a StreamInterface object.
267
     *
268
     * This method MUST be implemented in such a way as to retain the
269
     * immutability of the message, and MUST return a new instance that has the
270
     * new body stream.
271
     *
272
     * @param StreamInterface $body Body.
273
     * @return static
274
     * @throws \InvalidArgumentException When the body is not valid.
275
     */
276
    public function withBody(StreamInterface $body)
277
    {
278
        $message = clone $this;
279
        $message->body = $body;
280
        return $message;
281
    }
282
283
    /**
284
     * Get the original (preserved) header name for provided name
285
     *
286
     * @param $name
287
     * @return mixed
288
     */
289
    protected function headerKey($name)
290
    {
291
        $key = $name;
292
        foreach (array_keys($this->headers) as $existingName) {
293
            if (strtolower($name) == strtolower($existingName)) {
294
                $key = $existingName;
295
                break;
296
            }
297
        }
298
        return $key;
299
    }
300
}
301