Completed
Push — master ( e33e66...44de45 )
by Tobias
03:12
created

MessageTrait::withBody()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 11
ccs 6
cts 6
cp 1
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 6
nc 2
nop 1
crap 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Nyholm\Psr7;
6
7
use Nyholm\Psr7\Factory\StreamFactory;
8
use Psr\Http\Message\StreamInterface;
9
10
/**
11
 * Trait implementing functionality common to requests and responses.
12
 *
13
 * @author Michael Dowling and contributors to guzzlehttp/psr7
14
 * @author Tobias Nyholm <[email protected]>
15
 */
16
trait MessageTrait
17
{
18
    /** @var array Map of all registered headers, as original name => array of values */
19
    private $headers = [];
20
21
    /** @var array Map of lowercase header name => original name at registration */
22
    private $headerNames = [];
23
24
    /** @var string */
25
    private $protocol = '1.1';
26
27
    /** @var StreamInterface */
28
    private $stream;
29
30 5
    public function getProtocolVersion()
31
    {
32 5
        return $this->protocol;
33
    }
34
35 4
    public function withProtocolVersion($version)
36
    {
37 4
        if ($this->protocol === $version) {
38 1
            return $this;
39
        }
40
41 3
        $new = clone $this;
42 3
        $new->protocol = $version;
43
44 3
        return $new;
45
    }
46
47 16
    public function getHeaders(): array
48
    {
49 16
        return $this->headers;
50
    }
51
52 65
    public function hasHeader($header): bool
53
    {
54 65
        return isset($this->headerNames[strtolower($header)]);
55
    }
56
57 25
    public function getHeader($header): array
58
    {
59 25
        $header = strtolower($header);
60
61 25
        if (!isset($this->headerNames[$header])) {
62 5
            return [];
63
        }
64
65 24
        $header = $this->headerNames[$header];
66
67 24
        return $this->headers[$header];
68
    }
69
70 23
    public function getHeaderLine($header): string
71
    {
72 23
        return implode(', ', $this->getHeader($header));
73
    }
74
75 6
    public function withHeader($header, $value): self
76
    {
77 6 View Code Duplication
        if (!is_array($value)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
78 5
            $value = [$value];
79
        } elseif (empty($value)) {
80
            throw new \InvalidArgumentException('Header values must be non-empty strings');
81
        }
82
83 6
        if (!is_string($header) || empty($header)) {
84
            throw new \InvalidArgumentException('Header name must be non-empty strings');
85
        }
86
87 6 View Code Duplication
        foreach ($value as $v) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
88 6
            if (!is_string($v) || '' === trim($v)) {
89 6
                throw new \InvalidArgumentException('Header values must be non-empty strings');
90
            }
91
        }
92
93 6
        $value = $this->trimHeaderValues($value);
94 6
        $normalized = strtolower($header);
95
96 6
        $new = clone $this;
97 6
        if (isset($new->headerNames[$normalized])) {
98 1
            unset($new->headers[$new->headerNames[$normalized]]);
99
        }
100 6
        $new->headerNames[$normalized] = $header;
101 6
        $new->headers[$header] = $value;
102
103 6
        return $new;
104
    }
105
106 20
    public function withAddedHeader($header, $value): self
107
    {
108 20 View Code Duplication
        if (!is_array($value)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
109 17
            $value = [$value];
110 5
        } elseif (!empty($value)) {
111 5
            $value = array_values($value);
112
        } else {
113
            throw new \InvalidArgumentException('Header values must be non-empty strings');
114
        }
115
116 20
        if (!is_string($header) || empty($header)) {
117
            throw new \InvalidArgumentException('Header name must be non-empty strings');
118
        }
119
120 20 View Code Duplication
        foreach ($value as $v) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
121 20
            if (!is_string($v) || '' === trim($v)) {
122 20
                throw new \InvalidArgumentException('Header values must be non-empty strings');
123
            }
124
        }
125
126 20
        $value = $this->trimHeaderValues($value);
127 20
        $normalized = strtolower($header);
128
129 20
        $new = clone $this;
130 20
        if (isset($new->headerNames[$normalized])) {
131 14
            $header = $this->headerNames[$normalized];
132 14
            $new->headers[$header] = array_merge($this->headers[$header], $value);
133
        } else {
134 18
            $new->headerNames[$normalized] = $header;
135 18
            $new->headers[$header] = $value;
136
        }
137
138 20
        return $new;
139
    }
140
141 5
    public function withoutHeader($header): self
142
    {
143 5
        $normalized = strtolower($header);
144
145 5
        if (!isset($this->headerNames[$normalized])) {
146 2
            return $this;
147
        }
148
149 3
        $header = $this->headerNames[$normalized];
150
151 3
        $new = clone $this;
152 3
        unset($new->headers[$header], $new->headerNames[$normalized]);
153
154 3
        return $new;
155
    }
156
157 9
    public function getBody(): StreamInterface
158
    {
159 9
        if (!$this->stream) {
160 3
            $this->stream = (new StreamFactory())->createStream('');
161
        }
162
163 9
        return $this->stream;
164
    }
165
166 4
    public function withBody(StreamInterface $body): self
167
    {
168 4
        if ($body === $this->stream) {
169 1
            return $this;
170
        }
171
172 3
        $new = clone $this;
173 3
        $new->stream = $body;
174
175 3
        return $new;
176
    }
177
178 106
    private function setHeaders(array $headers)
179
    {
180 106
        $this->headerNames = $this->headers = [];
181 106
        foreach ($headers as $header => $value) {
182 11
            if (!is_array($value)) {
183 10
                $value = [$value];
184
            }
185
186 11
            $value = $this->trimHeaderValues($value);
187 11
            $normalized = strtolower($header);
188 11
            if (isset($this->headerNames[$normalized])) {
189
                $header = $this->headerNames[$normalized];
190
                $this->headers[$header] = array_merge($this->headers[$header], $value);
191
            } else {
192 11
                $this->headerNames[$normalized] = $header;
193 11
                $this->headers[$header] = $value;
194
            }
195
        }
196 106
    }
197
198
    /**
199
     * Trims whitespace from the header values.
200
     *
201
     * Spaces and tabs ought to be excluded by parsers when extracting the field value from a header field.
202
     *
203
     * header-field = field-name ":" OWS field-value OWS
204
     * OWS          = *( SP / HTAB )
205
     *
206
     * @param string[] $values Header values
207
     *
208
     * @return string[] Trimmed header values
209
     *
210
     * @see https://tools.ietf.org/html/rfc7230#section-3.2.4
211
     */
212
    private function trimHeaderValues(array $values): array
213
    {
214 29
        return array_map(function ($value) {
215 29
            return trim($value, " \t");
216 29
        }, $values);
217
    }
218
}
219