RequestTrait   A
last analyzed

Complexity

Total Complexity 17

Size/Duplication

Total Lines 252
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 2

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 17
lcom 2
cbo 2
dl 0
loc 252
ccs 50
cts 50
cp 1
rs 10
c 0
b 0
f 0

11 Methods

Rating   Name   Duplication   Size   Complexity  
hasHeader() 0 1 ?
getHeader() 0 1 ?
provideHeaders() 0 1 ?
A getRequestTarget() 0 14 4
A withRequestTarget() 0 7 1
A getMethod() 0 4 1
A withMethod() 0 9 1
A getUri() 0 4 1
A withUri() 0 17 4
A shouldSetHost() 0 4 3
A validateMethod() 0 18 2
1
<?php
2
namespace Kambo\Http\Message;
3
4
// \Spl
5
use InvalidArgumentException;
6
7
// \Psr
8
use Psr\Http\Message\UriInterface;
9
10
/**
11
 * Shared methods for outgoing, client-side request and server request.
12
 *
13
 * @package Kambo\Http\Message
14
 * @author  Bohuslav Simek <[email protected]>
15
 * @license MIT
16
 */
17
trait RequestTrait
18
{
19
    /**
20
     * Message request target
21
     *
22
     * @var string
23
     */
24
    private $requestTarget = null;
25
26
    /**
27
     * Method of incoming request - GET, POST, DELETE, PUT, PATCH, HEAD or OPTIONS.
28
     *
29
     * @var string
30
     */
31
    protected $requestMethod;
32
33
    /**
34
     * Uri of incoming request
35
     *
36
     * @var Psr\Http\Message\UriInterface;
37
     */
38
    protected $uri;
39
40
    /**
41
     * Checks if a header exists by the given case-insensitive name.
42
     *
43
     * @param string $name Case-insensitive header field name.
44
     *
45
     * @return bool Returns true if any header names match the given header name using
46
     *              a case-insensitive string comparison. Returns false if no matching
47
     *              header name is found in the message.
48
     */
49
    abstract public function hasHeader($name);
50
51
    /**
52
     * Retrieves a message header value by the given case-insensitive name.
53
     *
54
     * This method returns an array of all the header values of the given
55
     * case-insensitive header name.
56
     *
57
     * If the header does not appear in the message, this method return an
58
     * empty array.
59
     *
60
     * @param string $name Case-insensitive header field name.
61
     *
62
     * @return string[] An array of string values as provided for the given header.
63
     *                  If the header does not appear in the message, this method MUST
64
     *                  return an empty array.
65
     */
66
    abstract public function getHeader($name);
67
68
    /**
69
     * Provide message headers
70
     *
71
     * @return Headers Message headers
72
     */
73
    abstract protected function provideHeaders();
74
75
    /**
76
     * Retrieves the message's request target.
77
     *
78
     * Retrieves the message's request-target either as it will appear (for
79
     * clients), as it appeared at request (for servers), or as it was
80
     * specified for the instance (see withRequestTarget()).
81
     *
82
     * In most cases, this will be the origin-form of the composed URI,
83
     * unless a value was provided to the concrete implementation (see
84
     * withRequestTarget() below).
85
     *
86
     * If no URI is available, and no request-target has been specifically
87
     * provided, this method return the string "/".
88
     *
89
     * @return string
90
     */
91 4
    public function getRequestTarget()
92
    {
93 4
        if ($this->requestTarget === null) {
94 4
            $target = '/';
95 4
            if ($this->uri->getPath() !== null) {
96 4
                $target = $this->uri->getPath();
97 4
                $target .= (!empty($this->uri->getQuery())) ? '?' . $this->uri->getQuery() : '';
98 4
            }
99
100 4
            $this->requestTarget = $target;
101 4
        }
102
103 4
        return $this->requestTarget;
104
    }
105
106
    /**
107
     * Return an instance with the specific request-target.
108
     *
109
     * If the request needs a non-origin-form request-target — e.g., for
110
     * specifying an absolute-form, authority-form, or asterisk-form —
111
     * this method may be used to create an instance with the specified
112
     * request-target, verbatim.
113
     *
114
     * This method retains the state of the current instance, and return
115
     * an instance that has the changed request target.
116
     *     
117
     * @link http://tools.ietf.org/html/rfc7230#section-2.7 (for the various
118
     *       request-target forms allowed in request messages)
119
     *
120
     * @param mixed $requestTarget
121
     *
122
     * @return self
123
     */
124 2
    public function withRequestTarget($requestTarget)
125
    {
126 2
        $clone                = clone $this;
127 2
        $clone->requestTarget = $requestTarget;
128
129 2
        return $clone;
130
    }
131
132
    /**
133
     * Retrieves the HTTP method of the request.
134
     *
135
     * @return string Returns the request method.
136
     */
137 4
    public function getMethod()
138
    {
139 4
        return $this->requestMethod;
140
    }
141
142
    /**
143
     * Return an instance with the provided HTTP method.
144
     *
145
     * While HTTP method names are typically all uppercase characters, HTTP
146
     * method names are case-sensitive and thus implementations not
147
     * modify the given string.
148
     *
149
     * This method retains the state of the current instance, and return
150
     * an instance that changed request method.
151
     *
152
     * @param string $method Case-sensitive method.
153
     *
154
     * @return self
155
     *
156
     * @throws \InvalidArgumentException for invalid HTTP methods.
157
     */
158 4
    public function withMethod($method)
159
    {
160 4
        $this->validateMethod($method);
161
162 2
        $clone                = clone $this;
163 2
        $clone->requestMethod = $method;
164
165 2
        return $clone;
166
    }
167
168
    /**
169
     * Retrieves the URI instance.
170
     *
171
     * This method return a UriInterface instance.
172
     *
173
     * @link http://tools.ietf.org/html/rfc3986#section-4.3
174
     *
175
     * @return UriInterface Returns a UriInterface instance representing the URI of the request.                
176
     */
177 7
    public function getUri()
178
    {
179 7
        return $this->uri;
180
    }
181
182
    /**
183
     * Returns an instance with the provided URI.
184
     *
185
     * This method update the Host header of the returned request by
186
     * default if the URI contains a host component. If the URI does not
187
     * contain a host component, any pre-existing Host header is carried
188
     * over to the returned request.
189
     *
190
     * You can opt-in to preserving the original state of the Host header by
191
     * setting `$preserveHost` to `true`. When `$preserveHost` is set to
192
     * `true`, this method interacts with the Host header in the following ways:
193
     *
194
     * - If the the Host header is missing or empty, and the new URI contains
195
     *   a host component, this method update the Host header in the returned
196
     *   request.
197
     * - If the Host header is missing or empty, and the new URI does not contain a
198
     *   host component, this method not update the Host header in the returned
199
     *   request.
200
     * - If a Host header is present and non-empty, this method not update
201
     *   the Host header in the returned request.
202
     *
203
     * This method retains the state of the current instance, and return
204
     * an instance that contains the new UriInterface instance.
205
     *     
206
     * @link http://tools.ietf.org/html/rfc3986#section-4.3
207
     *
208
     * @param UriInterface $uri          New request URI to use.
209
     * @param bool         $preserveHost Preserve the original state of the Host header.
210
     *
211
     * @return self
212
     */
213 4
    public function withUri(UriInterface $uri, $preserveHost = false)
214
    {
215 4
        $clone      = clone $this;
216 4
        $clone->uri = $uri;
217
218 4
        if (!$preserveHost) {
219 2
            if ($uri->getHost() !== '') {
220 2
                $clone->provideHeaders()->set('Host', $uri->getHost());
221 2
            }
222 2
        } else {
223 2
            if ($this->shouldSetHost()) {
224 1
                $clone->provideHeaders()->set('Host', $uri->getHost());
225 1
            }
226
        }
227
228 4
        return $clone;
229
    }
230
231
    /**
232
     * Check if the host header should be set.
233
     *
234
     * @return bool true if should be
235
     */
236 11
    protected function shouldSetHost()
237
    {
238 11
        return $this->uri->getHost() !== '' && (!$this->hasHeader('Host') || $this->getHeader('Host') === null);
239
    }
240
241
    /**
242
     * Validate request method.
243
     *
244
     * @param string $method Case-sensitive request method.
245
     *
246
     * @return void
247
     *
248
     * @throws \InvalidArgumentException for invalid HTTP methods.
249
     */
250 11
    protected function validateMethod($method)
251
    {
252
        $valid = [
253 11
            'GET'     => true,
254 11
            'POST'    => true,
255 11
            'DELETE'  => true,
256 11
            'PUT'     => true,
257 11
            'PATCH'   => true,
258 11
            'HEAD'    => true,
259 11
            'OPTIONS' => true,
260 11
        ];
261
262 11
        if (!isset($valid[$method])) {
263 1
            throw new InvalidArgumentException(
264
                'Invalid method version. Must be one of: GET, POST, DELETE, PUT, PATCH, HEAD or OPTIONS'
265 1
            );
266
        }
267 11
    }
268
}
269