Message::hasHeader()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 3
rs 10
1
<?php declare(strict_types=1);
2
3
namespace One\Http;
4
5
class Message implements \Psr\Http\Message\MessageInterface
6
{
7
    /**
8
     * Headers
9
     * @var array<string[]>
10
     */
11
    protected $headers = [];
12
13
    /**
14
     * Header names
15
     * @var array<string[]>
16
     */
17
    protected $headerNames = [];
18
19
    /**
20
     * Protocol version
21
     * @var string
22
     */
23
    protected $protocol = '1.1';
24
25
    /**
26
     * Stream
27
     * @var \Psr\Http\Message\StreamInterface
28
     */
29
    protected $stream;
30
31
    /**
32
     * @inheritDoc
33
     */
34
    public function getProtocolVersion()
35
    {
36
        return $this->protocol;
37
    }
38
39
    /**
40
     * @inheritDoc
41
     */
42
    public function withProtocolVersion($version)
43
    {
44
        if ($this->protocol === $version) {
45
            return $this;
46
        }
47
48
        $new = clone $this;
49
50
        $new->protocol = $version;
51
52
        return $new;
53
    }
54
55
    /**
56
     * @inheritDoc
57
     */
58
    public function getHeaders()
59
    {
60
        return $this->headers;
61
    }
62
63
    /**
64
     * @inheritDoc
65
     */
66
    public function hasHeader($name)
67
    {
68
        return isset($this->headerNames[strtolower($name)]);
69
    }
70
71
    /**
72
     * @inheritDoc
73
     */
74
    public function getHeader($name)
75
    {
76
        $lower = strtolower($name);
77
78
        if (! isset($this->headerNames[$lower])) {
79
            return [];
80
        }
81
82
        return $this->headers[$this->headerNames[$lower]];
83
    }
84
85
    /**
86
     * @inheritDoc
87
     */
88
    public function getHeaderLine($header)
89
    {
90
        return implode(', ', $this->getHeader($header));
91
    }
92
93
    /**
94
     * @inheritDoc
95
     */
96
    public function withHeader($header, $value)
97
    {
98
        if (! is_array($value)) {
99
            $value = [$value];
100
        }
101
        $value = $this->trimHeaderValues($value);
102
        $normalized = strtolower($header);
103
        $new = clone $this;
104
        if (isset($new->headerNames[$normalized])) {
105
            unset($new->headers[$new->headerNames[$normalized]]);
106
        }
107
        $new->headerNames[$normalized] = $header;
108
        $new->headers[$header] = $value;
109
        return $new;
110
    }
111
112
    /**
113
     * @inheritDoc
114
     */
115
    public function withAddedHeader($header, $value)
116
    {
117
        if (! is_array($value)) {
118
            $value = [$value];
119
        }
120
        $value = $this->trimHeaderValues($value);
121
        $normalized = strtolower($header);
122
        $new = clone $this;
123
        if (isset($new->headerNames[$normalized])) {
124
            $header = $this->headerNames[$normalized];
125
            $new->headers[$header] = array_merge($this->headers[$header], $value);
126
        } else {
127
            $new->headerNames[$normalized] = $header;
128
            $new->headers[$header] = $value;
129
        }
130
        return $new;
131
    }
132
133
    /**
134
     * @inheritDoc
135
     */
136
    public function withoutHeader($header)
137
    {
138
        $normalized = strtolower($header);
139
        if (! isset($this->headerNames[$normalized])) {
140
            return $this;
141
        }
142
        $header = $this->headerNames[$normalized];
143
        $new = clone $this;
144
        unset($new->headers[$header], $new->headerNames[$normalized]);
145
        return $new;
146
    }
147
148
    /**
149
     * @inheritDoc
150
     */
151
    public function getBody()
152
    {
153
        if (! $this->stream) {
154
            $this->stream = \One\stream_for('');
155
        }
156
        return $this->stream;
157
    }
158
159
    /**
160
     * @inheritDoc
161
     */
162
    public function withBody(\Psr\Http\Message\StreamInterface $body)
163
    {
164
        if ($body === $this->stream) {
165
            return $this;
166
        }
167
        $new = clone $this;
168
        $new->stream = $body;
169
        return $new;
170
    }
171
172
    /**
173
     * Set header
174
     */
175
    protected function setHeaders(array $headers): void
176
    {
177
        $this->headerNames = $this->headers = [];
178
        foreach ($headers as $header => $value) {
179
            if (! is_array($value)) {
180
                $value = [$value];
181
            }
182
            $value = $this->trimHeaderValues($value);
183
            $normalized = strtolower($header);
184
            if (isset($this->headerNames[$normalized])) {
185
                $header = $this->headerNames[$normalized];
186
                $this->headers[$header] = array_merge($this->headers[$header], $value);
187
            } else {
188
                $this->headerNames[$normalized] = $header;
189
                $this->headers[$header] = $value;
190
            }
191
        }
192
    }
193
194
    /**
195
     * Trims whitespace from the header values.
196
     *
197
     * Spaces and tabs ought to be excluded by parsers when extracting the field value from a header field.
198
     *
199
     * header-field = field-name ":" OWS field-value OWS
200
     * OWS          = *( SP / HTAB )
201
     *
202
     * @param string[] $values Header values
203
     *
204
     * @return string[] Trimmed header values
205
     *
206
     * @see https://tools.ietf.org/html/rfc7230#section-3.2.4
207
     */
208
    protected function trimHeaderValues(array $values): array
209
    {
210
        return array_map(function ($value) {
211
            return trim($value, " \t");
212
        }, $values);
213
    }
214
}
215