Passed
Push — main ( 189a60...255c0f )
by Yevhenii
02:11
created

AbstractMessage   A

Complexity

Total Complexity 31

Size/Duplication

Total Lines 274
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 31
eloc 62
c 1
b 0
f 0
dl 0
loc 274
ccs 0
cts 71
cp 0
rs 9.92

15 Methods

Rating   Name   Duplication   Size   Complexity  
A getHeaderAsArray() 0 9 2
B getBodyAsString() 0 24 7
A getHeader() 0 9 2
A setBody() 0 3 1
A getHeaders() 0 8 2
A setHeader() 0 3 1
A getBodyAsStream() 0 15 4
A getBody() 0 3 1
A addHeaders() 0 4 2
A hasHeader() 0 3 1
A addHeader() 0 12 2
A removeHeader() 0 9 2
A setHttpVersion() 0 3 1
A setHeaders() 0 4 2
A getHttpVersion() 0 3 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace SteamMarketProviders\ParserManager\Http;
6
7
use SteamMarketProviders\ParserManager\Contract\Http\MessageInterface;
8
9
abstract class AbstractMessage implements MessageInterface
10
{
11
    /**
12
     * Request body.
13
     *
14
     * This should be a stream resource, string or a callback writing the body to php://output
15
     *
16
     * @var resource|string|callable
17
     */
18
    protected $body;
19
20
    /**
21
     * Contains the list of HTTP headers.
22
     *
23
     * @var array
24
     */
25
    protected $headers = [];
26
27
    /**
28
     * HTTP message version (1.0, 1.1 or 2.0).
29
     *
30
     * @var string
31
     */
32
    protected $httpVersion = '1.1';
33
34
    /**
35
     * Returns the body as a readable stream resource.
36
     *
37
     * Note that the stream may not be rewindable, and therefore may only be
38
     * read once.
39
     *
40
     * @return resource
41
     */
42
    public function getBodyAsStream()
43
    {
44
        $body = $this->getBody();
45
        if (is_callable($this->body)) {
46
            $body = $this->getBodyAsString();
47
        }
48
        if (is_string($body) || null === $body) {
49
            $stream = fopen('php://temp', 'r+');
50
            fwrite($stream, (string) $body);
51
            rewind($stream);
52
53
            return $stream;
54
        }
55
56
        return $body;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $body also could return the type callable which is incompatible with the documented return type resource.
Loading history...
57
    }
58
59
    /**
60
     * Returns the body as a string.
61
     *
62
     * Note that because the underlying data may be based on a stream, this
63
     * method could only work correctly the first time.
64
     */
65
    public function getBodyAsString(): string
66
    {
67
        $body = $this->getBody();
68
        if (is_string($body)) {
69
            return $body;
70
        }
71
        if (null === $body) {
0 ignored issues
show
introduced by
The condition null === $body is always false.
Loading history...
72
            return '';
73
        }
74
        if (is_callable($body)) {
75
            ob_start();
76
            $body();
77
78
            return ob_get_clean();
79
        }
80
        /**
81
         * @var string|int|null
82
         */
83
        $contentLength = $this->getHeader('Content-Length');
84
        if (null !== $contentLength && (is_int($contentLength) || ctype_digit($contentLength))) {
85
            return stream_get_contents($body, (int) $contentLength);
0 ignored issues
show
Bug introduced by
It seems like $body can also be of type callable; however, parameter $stream of stream_get_contents() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

85
            return stream_get_contents(/** @scrutinizer ignore-type */ $body, (int) $contentLength);
Loading history...
86
        }
87
88
        return stream_get_contents($body);
89
    }
90
91
    /**
92
     * Returns the message body, as it's internal representation.
93
     *
94
     * This could be either a string, a stream or a callback writing the body to php://output.
95
     *
96
     * @return resource|string|callable
97
     */
98
    public function getBody()
99
    {
100
        return $this->body;
101
    }
102
103
    /**
104
     * Replaces the body resource with a new stream, string or a callback writing the body to php://output.
105
     *
106
     * @param resource|string|callable $body
107
     */
108
    public function setBody($body)
109
    {
110
        $this->body = $body;
111
    }
112
113
    /**
114
     * Returns all the HTTP headers as an array.
115
     *
116
     * Every header is returned as an array, with one or more values.
117
     */
118
    public function getHeaders(): array
119
    {
120
        $result = [];
121
        foreach ($this->headers as $headerInfo) {
122
            $result[$headerInfo[0]] = $headerInfo[1];
123
        }
124
125
        return $result;
126
    }
127
128
    /**
129
     * Will return true or false, depending on if a HTTP header exists.
130
     */
131
    public function hasHeader(string $name): bool
132
    {
133
        return isset($this->headers[strtolower($name)]);
134
    }
135
136
    /**
137
     * Returns a specific HTTP header, based on it's name.
138
     *
139
     * The name must be treated as case-insensitive.
140
     * If the header does not exist, this method must return null.
141
     *
142
     * If a header appeared more than once in a HTTP request, this method will
143
     * concatenate all the values with a comma.
144
     *
145
     * Note that this not make sense for all headers. Some, such as
146
     * `Set-Cookie` cannot be logically combined with a comma. In those cases
147
     * you *should* use getHeaderAsArray().
148
     *
149
     * @return string|null
150
     */
151
    public function getHeader(string $name)
152
    {
153
        $name = strtolower($name);
154
155
        if (isset($this->headers[$name])) {
156
            return implode(',', $this->headers[$name][1]);
157
        }
158
159
        return null;
160
    }
161
162
    /**
163
     * Returns a HTTP header as an array.
164
     *
165
     * For every time the HTTP header appeared in the request or response, an
166
     * item will appear in the array.
167
     *
168
     * If the header did not exists, this method will return an empty array.
169
     *
170
     * @return string[]
171
     */
172
    public function getHeaderAsArray(string $name): array
173
    {
174
        $name = strtolower($name);
175
176
        if (isset($this->headers[$name])) {
177
            return $this->headers[$name][1];
178
        }
179
180
        return [];
181
    }
182
183
    /**
184
     * Updates a HTTP header.
185
     *
186
     * The case-sensitivity of the name value must be retained as-is.
187
     *
188
     * If the header already existed, it will be overwritten.
189
     *
190
     * @param string|string[] $value
191
     */
192
    public function setHeader(string $name, $value)
193
    {
194
        $this->headers[strtolower($name)] = [$name, (array) $value];
195
    }
196
197
    /**
198
     * Sets a new set of HTTP headers.
199
     *
200
     * The headers array should contain headernames for keys, and their value
201
     * should be specified as either a string or an array.
202
     *
203
     * Any header that already existed will be overwritten.
204
     */
205
    public function setHeaders(array $headers)
206
    {
207
        foreach ($headers as $name => $value) {
208
            $this->setHeader($name, $value);
209
        }
210
    }
211
212
    /**
213
     * Adds a HTTP header.
214
     *
215
     * This method will not overwrite any existing HTTP header, but instead add
216
     * another value. Individual values can be retrieved with
217
     * getHeadersAsArray.
218
     *
219
     * @param string|string[] $value
220
     */
221
    public function addHeader(string $name, $value)
222
    {
223
        $lName = strtolower($name);
224
        if (isset($this->headers[$lName])) {
225
            $this->headers[$lName][1] = array_merge(
226
                $this->headers[$lName][1],
227
                (array) $value
228
            );
229
        } else {
230
            $this->headers[$lName] = [
231
                $name,
232
                (array) $value,
233
            ];
234
        }
235
    }
236
237
    /**
238
     * Adds a new set of HTTP headers.
239
     *
240
     * Any existing headers will not be overwritten.
241
     */
242
    public function addHeaders(array $headers)
243
    {
244
        foreach ($headers as $name => $value) {
245
            $this->addHeader($name, $value);
246
        }
247
    }
248
249
    /**
250
     * Removes a HTTP header.
251
     *
252
     * The specified header name must be treated as case-insensitive.
253
     * This method should return true if the header was successfully deleted,
254
     * and false if the header did not exist.
255
     */
256
    public function removeHeader(string $name): bool
257
    {
258
        $name = strtolower($name);
259
        if (!isset($this->headers[$name])) {
260
            return false;
261
        }
262
        unset($this->headers[$name]);
263
264
        return true;
265
    }
266
267
    /**
268
     * Sets the HTTP version.
269
     *
270
     * Should be 1.0, 1.1 or 2.0.
271
     */
272
    public function setHttpVersion(string $version)
273
    {
274
        $this->httpVersion = $version;
275
    }
276
277
    /**
278
     * Returns the HTTP version.
279
     */
280
    public function getHttpVersion(): string
281
    {
282
        return $this->httpVersion;
283
    }
284
}