AbstractMessage::withHeader()   A
last analyzed

Complexity

Conditions 2
Paths 1

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 5
c 1
b 0
f 0
nc 1
nop 2
dl 0
loc 7
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Cakasim\Payone\Sdk\Http\Message;
6
7
use Psr\Http\Message\MessageInterface;
8
use Psr\Http\Message\StreamInterface;
9
10
/**
11
 * The base class for HTTP messages.
12
 *
13
 * @author Fabian Böttcher <[email protected]>
14
 * @since 0.1.0
15
 */
16
abstract class AbstractMessage implements MessageInterface
17
{
18
    public const PROTOCOL_VERSION_1_0 = '1.0';
19
    public const PROTOCOL_VERSION_1_1 = '1.1';
20
    public const PROTOCOL_VERSION_2 = '2';
21
22
    /**
23
     * @var string The HTTP protocol version.
24
     */
25
    protected $protocolVersion;
26
27
    /**
28
     * @var string[][] The HTTP headers.
29
     */
30
    protected $headers = [];
31
32
    /**
33
     * @var StreamInterface The HTTP body.
34
     */
35
    protected $body;
36
37
    /**
38
     * Constructs a message.
39
     *
40
     * @param string $protocolVersion The HTTP protocol version.
41
     * @param StreamInterface $body The message body.
42
     * @param array $headers The message headers.
43
     */
44
    public function __construct(string $protocolVersion, StreamInterface $body, array $headers)
45
    {
46
        $this->setProtocolVersion($protocolVersion);
47
        $this->setBody($body);
48
49
        // Parse message headers to internal format.
50
        foreach ($headers as $name => $values) {
51
            $this->headers[strtolower($name)] = is_array($values)
52
                ? [$name, $values]
53
                : [$name, [$values]];
54
        }
55
    }
56
57
    /**
58
     * Perform deep copy of attributes.
59
     */
60
    public function __clone()
61
    {
62
        $this->body = clone $this->body;
63
    }
64
65
    /**
66
     * @inheritDoc
67
     */
68
    public function getProtocolVersion()
69
    {
70
        return $this->protocolVersion;
71
    }
72
73
    /**
74
     * Sets the HTTP protocol version.
75
     *
76
     * @param string $protocolVersion The HTTP protocol version.
77
     * @return $this
78
     */
79
    protected function setProtocolVersion(string $protocolVersion): self
80
    {
81
        $this->protocolVersion = $protocolVersion;
82
        return $this;
83
    }
84
85
    /**
86
     * @inheritDoc
87
     */
88
    public function withProtocolVersion($version)
89
    {
90
        return (clone $this)->setProtocolVersion($version);
91
    }
92
93
    /**
94
     * @inheritDoc
95
     */
96
    public function getHeaders()
97
    {
98
        $headers = [];
99
100
        foreach ($this->headers as $header) {
101
            $headers[$header[0]] = $header[1];
102
        }
103
104
        return $headers;
105
    }
106
107
    /**
108
     * @inheritDoc
109
     */
110
    public function hasHeader($name)
111
    {
112
        return isset($this->headers[strtolower($name)]);
113
    }
114
115
    /**
116
     * @inheritDoc
117
     */
118
    public function getHeader($name)
119
    {
120
        return $this->headers[strtolower($name)][1] ?? [];
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->headers[st...r($name)][1] ?? array() also could return the type string which is incompatible with the return type mandated by Psr\Http\Message\MessageInterface::getHeader() of string[].
Loading history...
121
    }
122
123
    /**
124
     * Sets a header field.
125
     *
126
     * @param string $name The name of the header.
127
     * @param string[] $value The values of the header.
128
     * @return $this
129
     */
130
    protected function setHeader(string $name, array $value): self
131
    {
132
        $this->headers[strtolower($name)] = [$name, array_filter($value, function ($item) {
133
            // Filter non and empty strings.
134
            return is_string($item) && !empty($item);
135
        })];
136
137
        return $this;
138
    }
139
140
    /**
141
     * Adds a value to an existing header field.
142
     *
143
     * @param string $name The name of the existing header.
144
     * @param string[] $value The values to add to the existing header.
145
     * @return $this
146
     */
147
    protected function addHeader(string $name, array $value): self
148
    {
149
        $this->setHeader(
150
            $name,
151
            $this->hasHeader($name)
152
                ? array_merge($this->getHeader($name), $value)
0 ignored issues
show
Bug introduced by
It seems like $this->getHeader($name) can also be of type string; however, parameter $array1 of array_merge() does only seem to accept array, 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

152
                ? array_merge(/** @scrutinizer ignore-type */ $this->getHeader($name), $value)
Loading history...
153
                : $value
154
        );
155
156
        return $this;
157
    }
158
159
    /**
160
     * Removes an existing header field.
161
     *
162
     * @param string $name The name of the header.
163
     * @return $this
164
     */
165
    protected function removeHeader(string $name): self
166
    {
167
        unset($this->headers[strtolower($name)]);
168
        return $this;
169
    }
170
171
    /**
172
     * @inheritDoc
173
     */
174
    public function getHeaderLine($name)
175
    {
176
        return join(',', $this->getHeader($name));
0 ignored issues
show
Bug introduced by
It seems like $this->getHeader($name) can also be of type string; however, parameter $pieces of join() does only seem to accept array, 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

176
        return join(',', /** @scrutinizer ignore-type */ $this->getHeader($name));
Loading history...
177
    }
178
179
    /**
180
     * @inheritDoc
181
     */
182
    public function withHeader($name, $value)
183
    {
184
        return (clone $this)->setHeader(
185
            $name,
186
            is_array($value)
187
                ? $value
188
                : [$value]
189
        );
190
    }
191
192
    /**
193
     * @inheritDoc
194
     */
195
    public function withAddedHeader($name, $value)
196
    {
197
        return (clone $this)->addHeader(
198
            $name,
199
            is_array($value)
200
                ? $value
201
                : [$value]
202
        );
203
    }
204
205
    /**
206
     * @inheritDoc
207
     */
208
    public function withoutHeader($name)
209
    {
210
        return (clone $this)->removeHeader($name);
211
    }
212
213
    /**
214
     * @inheritDoc
215
     */
216
    public function getBody()
217
    {
218
        return $this->body;
219
    }
220
221
    /**
222
     * Sets the message body.
223
     *
224
     * @param StreamInterface $body The message body.
225
     * @return $this
226
     */
227
    protected function setBody(StreamInterface $body): self
228
    {
229
        $this->body = $body;
230
        return $this;
231
    }
232
233
    /**
234
     * @inheritDoc
235
     */
236
    public function withBody(StreamInterface $body)
237
    {
238
        return (clone $this)->setBody($body);
239
    }
240
}
241