• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

valkyrjaio / valkyrja / 12786029933

15 Jan 2025 10:09AM UTC coverage: 47.422% (+0.001%) from 47.421%
12786029933

push

github

MelechMizrachi
Adding more specific array types.

7 of 9 new or added lines in 4 files covered. (77.78%)

5179 of 10921 relevant lines covered (47.42%)

19.07 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.46
/src/Valkyrja/Http/Message/Message.php
1
<?php
2

3
declare(strict_types=1);
4

5
/*
6
 * This file is part of the Valkyrja Framework package.
7
 *
8
 * (c) Melech Mizrachi <melechmizrachi@gmail.com>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13

14
namespace Valkyrja\Http\Message;
15

16
use InvalidArgumentException;
17
use Valkyrja\Http\Message\Enum\ProtocolVersion;
18
use Valkyrja\Http\Message\Header\Security\HeaderSecurity;
19
use Valkyrja\Http\Message\Stream\Contract\Stream;
20

21
use function array_merge;
22
use function implode;
23
use function is_array;
24
use function strtolower;
25

26
/**
27
 * Trait MessageTrait.
28
 *
29
 * @author Melech Mizrachi
30
 */
31
trait Message
32
{
33
    /**
34
     * The headers with normalized header names.
35
     *
36
     * @var array<string, string[]>
37
     */
38
    protected array $headers = [];
39

40
    /**
41
     * Original header names.
42
     *
43
     * @var array<string, string>
44
     */
45
    protected array $headerNames = [];
46

47
    /**
48
     * The protocol version.
49
     *
50
     * @var ProtocolVersion
51
     */
52
    protected ProtocolVersion $protocolVersion = ProtocolVersion::V1_1;
53

54
    /**
55
     * The stream.
56
     *
57
     * @var Stream
58
     */
59
    protected Stream $stream;
60

61
    /**
62
     * @inheritDoc
63
     */
64
    public function getProtocolVersion(): ProtocolVersion
65
    {
66
        return $this->protocolVersion;
14✔
67
    }
68

69
    /**
70
     * @inheritDoc
71
     *
72
     * @return static
73
     */
74
    public function withProtocolVersion(ProtocolVersion $version): static
75
    {
76
        $new = clone $this;
6✔
77

78
        $new->protocolVersion = $version;
6✔
79

80
        return $new;
6✔
81
    }
82

83
    /**
84
     * @inheritDoc
85
     *
86
     * @return array<string, string[]>
87
     */
88
    public function getHeaders(): array
89
    {
90
        return $this->headers;
24✔
91
    }
92

93
    /**
94
     * @inheritDoc
95
     */
96
    public function hasHeader(string $name): bool
97
    {
98
        return isset($this->headerNames[strtolower($name)]);
368✔
99
    }
100

101
    /**
102
     * @inheritDoc
103
     *
104
     * @return string[]
105
     */
106
    public function getHeader(string $name): array
107
    {
108
        if (! $this->hasHeader($name)) {
50✔
109
            return [];
8✔
110
        }
111

112
        $name = $this->headerNames[strtolower($name)];
50✔
113

114
        return $this->headers[$name];
50✔
115
    }
116

117
    /**
118
     * @inheritDoc
119
     */
120
    public function getHeaderLine(string $name): string
121
    {
122
        $value = $this->getHeader($name);
46✔
123

124
        if (empty($value)) {
46✔
125
            return '';
8✔
126
        }
127

128
        return implode(',', $value);
46✔
129
    }
130

131
    /**
132
     * @inheritDoc
133
     *
134
     * @return static
135
     */
136
    public function withHeader(string $name, string ...$values): static
137
    {
138
        HeaderSecurity::assertValidName($name);
28✔
139

140
        $normalized = strtolower($name);
28✔
141

142
        $new = clone $this;
28✔
143

144
        if ($new->hasHeader($name)) {
28✔
145
            unset($new->headers[$new->headerNames[$normalized]]);
14✔
146
        }
147

148
        $new->headerNames[$normalized] = $name;
28✔
149

150
        $new->headers[$name] = $this->assertHeaderValues(...$values);
28✔
151

152
        return $new;
28✔
153
    }
154

155
    /**
156
     * @inheritDoc
157
     *
158
     * @param string ...$values Header value(s).
159
     *
160
     * @return static
161
     */
162
    public function withAddedHeader(string $name, string ...$values): static
163
    {
164
        HeaderSecurity::assertValidName($name);
10✔
165

166
        if (! $this->hasHeader($name)) {
10✔
167
            return $this->withHeader($name, ...$values);
6✔
168
        }
169

170
        $name = $this->headerNames[strtolower($name)];
6✔
171

172
        $new = clone $this;
6✔
173

174
        $new->headers[$name] = array_merge($this->headers[$name], $this->assertHeaderValues(...$values));
6✔
175

176
        return $new;
6✔
177
    }
178

179
    /**
180
     * @inheritDoc
181
     *
182
     * @return static
183
     */
184
    public function withoutHeader(string $name): static
185
    {
186
        if (! $this->hasHeader($name)) {
8✔
187
            return clone $this;
4✔
188
        }
189

190
        $normalized = strtolower($name);
6✔
191
        $original   = $this->headerNames[$normalized];
6✔
192
        $new        = clone $this;
6✔
193

194
        unset($new->headers[$original], $new->headerNames[$normalized]);
6✔
195

196
        return $new;
6✔
197
    }
198

199
    /**
200
     * @inheritDoc
201
     */
202
    public function getBody(): Stream
203
    {
204
        return $this->stream;
38✔
205
    }
206

207
    /**
208
     * @inheritDoc
209
     *
210
     * @return static
211
     */
212
    public function withBody(Stream $body): static
213
    {
214
        $new = clone $this;
10✔
215

216
        $new->setBody($body);
10✔
217

218
        $body->rewind();
10✔
219

220
        return $new;
10✔
221
    }
222

223
    public function __clone()
224
    {
225
        $this->stream = clone $this->stream;
60✔
226
    }
227

228
    /**
229
     * Set the body.
230
     *
231
     * @param Stream $body The body
232
     *
233
     * @return void
234
     */
235
    protected function setBody(Stream $body): void
236
    {
237
        $this->stream = $body;
428✔
238
    }
239

240
    /**
241
     * Set headers.
242
     *
243
     * @param array<string, string|string[]> $originalHeaders The original headers
244
     *
245
     * @throws InvalidArgumentException
246
     *
247
     * @return void
248
     */
249
    protected function setHeaders(array $originalHeaders): void
250
    {
251
        $headerNames = $headers = [];
426✔
252

253
        foreach ($originalHeaders as $header => $value) {
426✔
254
            $value = is_array($value) ? $value : [$value];
260✔
255

256
            HeaderSecurity::assertValidName($header);
260✔
257

258
            $headerNames[strtolower($header)] = $header;
260✔
259

260
            $headers[$header] = $this->assertHeaderValues(...$value);
260✔
261
        }
262

263
        $this->headerNames = $headerNames;
426✔
264
        $this->headers     = $headers;
426✔
265
    }
266

267
    /**
268
     * Filter header values.
269
     *
270
     * @param string ...$values Header values
271
     *
272
     * @throws InvalidArgumentException
273
     *
274
     * @return string[]
275
     */
276
    protected function assertHeaderValues(string ...$values): array
277
    {
278
        foreach ($values as $value) {
270✔
279
            HeaderSecurity::assertValid($value);
270✔
280
        }
281

282
        return $values;
270✔
283
    }
284

285
    /**
286
     * Inject a header in a headers array.
287
     *
288
     * @param string                       $header   The header to set
289
     * @param string                       $value    The value to set
290
     * @param array<string, string[]>|null $headers  [optional] The headers
291
     * @param bool                         $override [optional] Whether to override any existing value
292
     *
293
     * @return array<string, string[]>
294
     */
295
    protected function injectHeader(
296
        string $header,
297
        string $value,
298
        array|null $headers = null,
299
        bool $override = false
300
    ): array {
301
        // The headers
302
        $headers ??= [];
80✔
303
        // Normalize the content type header
304
        $normalized = strtolower($header);
80✔
305
        // The original value for the header (if it exists in the headers array)
306
        // Defaults to the value passed in
307
        $originalValue = [$value];
80✔
308

309
        // Iterate through all the headers
310
        foreach ($headers as $headerIndex => $headerValue) {
80✔
311
            // Normalize the header name and check if it matches the normalized
312
            // passed in header
313
            if (strtolower($headerIndex) === $normalized) {
36✔
314
                // Set the original value as this header value
315
                $originalValue = $headerValue;
20✔
316

317
                // Unset the header as we want to use the header string that was
318
                // passed in as the header
319
                unset($headers[$headerIndex]);
20✔
320
            }
321
        }
322

323
        // Set the header in the headers list
324
        $headers[$header] = $override
80✔
325
            ? [$value]
80✔
NEW
326
            : $originalValue;
×
327

328
        return $headers;
80✔
329
    }
330
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc