1<?php
2
3namespace iplx\Http;
4
5use Psr\Http\Message\StreamInterface;
6
7trait MessageTrait
8{
9    /**
10     * Case sensitive header names with lowercase header names as keys
11     *
12     * @var array
13     */
14    protected $headerNames = [];
15
16    /**
17     * Header values with lowercase header names as keys
18     *
19     * @var array
20     */
21    protected $headerValues = [];
22
23    /**
24     * The body of this request
25     *
26     * @var StreamInterface
27     */
28    protected $body;
29
30    /**
31     * Protocol version
32     *
33     * @var string
34     */
35    protected $protocolVersion;
36
37    public function getProtocolVersion()
38    {
39        return $this->protocolVersion;
40    }
41
42    public function withProtocolVersion($version)
43    {
44        $message = clone $this;
45        $message->protocolVersion = $version;
46
47        return $message;
48    }
49
50    public function getHeaders()
51    {
52        return array_combine($this->headerNames, $this->headerValues);
53    }
54
55    public function hasHeader($header)
56    {
57        return isset($this->headerValues[strtolower($header)]);
58    }
59
60    public function getHeader($header)
61    {
62        $header = strtolower($header);
63
64        if (! isset($this->headerValues[$header])) {
65            return [];
66        }
67
68        return $this->headerValues[$header];
69    }
70
71    public function getHeaderLine($name)
72    {
73        $name = strtolower($name);
74
75        if (! isset($this->headerValues[$name])) {
76            return '';
77        }
78
79        return implode(', ', $this->headerValues[$name]);
80    }
81
82    public function withHeader($name, $value)
83    {
84        $name = rtrim($name);
85
86        $value = $this->normalizeHeaderValues($value);
87
88        $normalized = strtolower($name);
89
90        $message = clone $this;
91        $message->headerNames[$normalized] = $name;
92        $message->headerValues[$normalized] = $value;
93
94        return $message;
95    }
96
97    public function withAddedHeader($name, $value)
98    {
99        $name = rtrim($name);
100
101        $value = $this->normalizeHeaderValues($value);
102
103        $normalized = strtolower($name);
104
105        $message = clone $this;
106        if (isset($message->headerNames[$normalized])) {
107            $message->headerValues[$normalized] = array_merge($message->headerValues[$normalized], $value);
108        } else {
109            $message->headerNames[$normalized] = $name;
110            $message->headerValues[$normalized] = $value;
111        }
112
113        return $message;
114    }
115
116    public function withoutHeader($name)
117    {
118        $normalized = strtolower(rtrim($name));
119
120        $message = clone $this;
121        unset($message->headerNames[$normalized]);
122        unset($message->headerValues[$normalized]);
123
124        return $message;
125    }
126
127    public function getBody()
128    {
129        return $this->body;
130    }
131
132    public function withBody(StreamInterface $body)
133    {
134        $message = clone $this;
135        $message->body = $body;
136
137        return $message;
138    }
139
140    protected function setHeaders(array $headers)
141    {
142        // Prepare header field names and header field values according to
143        // https://tools.ietf.org/html/rfc7230#section-3.2.4
144        $names = array_map('rtrim', array_keys($headers));
145        $values = $this->normalizeHeaderValues($headers);
146
147        $normalized = array_map('strtolower', $names);
148
149        $this->headerNames = array_combine(
150            $normalized,
151            $names
152        );
153
154        $this->headerValues = array_combine(
155            $normalized,
156            $values
157        );
158    }
159
160    protected function normalizeHeaderValues(array $values)
161    {
162        // Prepare header field names and header field values according to
163        // https://tools.ietf.org/html/rfc7230#section-3.2.4
164        return array_map(function ($value) {
165            if (! is_array($value)) {
166                $value = [$value];
167            }
168
169            return array_map(function ($value) {
170                return trim($value, " \t");
171            }, $value);
172        }, $values);
173    }
174}
175