Request::withMethod()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 1
dl 0
loc 6
ccs 0
cts 4
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Linna Http Message.
5
 *
6
 * @author Sebastian Rapetti <[email protected]>
7
 * @copyright (c) 2019, Sebastian Rapetti
8
 * @license http://opensource.org/licenses/MIT MIT License
9
 */
10
declare(strict_types=1);
11
12
namespace Linna\Http\Message;
13
14
use InvalidArgumentException;
15
use Psr\Http\Message\RequestInterface;
16
use Psr\Http\Message\UriInterface;
17
18
/**
19
 * PSR-7 Request implementation.
20
 */
21
class Request extends Message implements RequestInterface
22
{
23
    /**
24
     * @var string Request HTTP method (GET, POST, PUT.....).
25
     */
26
    protected $method = '';
27
28
    /**
29
     * @var string Request target.
30
     */
31
    protected $target = '';
32
33
    /**
34
     * @var UriInterface Request uri.
35
     */
36
    protected $uri;
37
38
    /**
39
     * Class Constructor.
40
     *
41
     * @param UriInterface $uri
42
     * @param string       $method
43
     * @param string       $body
44
     * @param array        $headers
45
     */
46 15
    public function __construct(UriInterface $uri, string $method = 'GET', string $body = 'php://memory', array $headers = [])
47
    {
48 15
        $this->uri = $uri;
49
50 15
        $this->method = $this->validateHttpMethod(\strtoupper($method));
51
52
        //from parent Message
53 14
        $this->body = new Stream($body, 'wb+');
54 14
        $this->headers = $headers;
55 14
    }
56
57
    /**
58
     * Validate HTTP Method
59
     *
60
     * @param string $method HTTP Method
61
     *
62
     * @return string
63
     *
64
     * @throws InvalidArgumentException if passed method is not an HTTP valid method.
65
     */
66 15
    private function validateHttpMethod(string $method): string
67
    {
68 15
        if (\in_array($method, [
69
            'GET',
70
            'HEAD',
71
            'POST',
72
            'PUT',
73
            'DELETE',
74
            'CONNECT',
75
            'OPTIONS',
76
            'TRACE'
77
            ])) {
78 14
            return $method;
79
        }
80
81 1
        throw new InvalidArgumentException('Invalid HTTP method.');
82
    }
83
84
    /**
85
     * Retrieves the message's request target.
86
     *
87
     * Retrieves the message's request-target either as it will appear (for
88
     * clients), as it appeared at request (for servers), or as it was
89
     * specified for the instance (see withRequestTarget()).
90
     *
91
     * In most cases, this will be the origin-form of the composed URI,
92
     * unless a value was provided to the concrete implementation (see
93
     * withRequestTarget() below).
94
     *
95
     * If no URI is available, and no request-target has been specifically
96
     * provided, this method MUST return the string "/".
97
     *
98
     * @return string
99
     */
100 12
    public function getRequestTarget(): string
101
    {
102 12
        if (!empty($this->target)) {
103 6
            return $this->target;
104
        }
105
106 6
        $target = $this->uri->getPath();
107 6
        $query = $this->uri->getQuery();
108
109 6
        if (!empty($query)) {
110 1
            $target .= "?{$query}";
111
        }
112
113 6
        if (empty($target)) {
114
            return '/';
115
        }
116
117 6
        return $target;
118
    }
119
120
    /**
121
     * Return an instance with the specific request-target.
122
     *
123
     * If the request needs a non-origin-form request-target — e.g., for
124
     * specifying an absolute-form, authority-form, or asterisk-form —
125
     * this method may be used to create an instance with the specified
126
     * request-target, verbatim.
127
     *
128
     * This method MUST be implemented in such a way as to retain the
129
     * immutability of the message, and MUST return an instance that has the
130
     * changed request target.
131
     *
132
     * @link http://tools.ietf.org/html/rfc7230#section-5.3 (for the various
133
     *       request-target forms allowed in request messages)
134
     *
135
     * @param mixed $requestTarget
136
     *
137
     * @return static
138
     */
139 6
    public function withRequestTarget(string $requestTarget): RequestInterface
140
    {
141 6
        $new = clone $this;
142 6
        $new->target = $requestTarget;
143
144 6
        return $new;
145
    }
146
147
    /**
148
     * Retrieves the HTTP method of the request.
149
     *
150
     * @return string Returns the request method.
151
     */
152
    public function getMethod(): string
153
    {
154
        return $this->method;
155
    }
156
157
    /**
158
     * Return an instance with the provided HTTP method.
159
     *
160
     * While HTTP method names are typically all uppercase characters, HTTP
161
     * method names are case-sensitive and thus implementations SHOULD NOT
162
     * modify the given string.
163
     *
164
     * This method MUST be implemented in such a way as to retain the
165
     * immutability of the message, and MUST return an instance that has the
166
     * changed request method.
167
     *
168
     * @param string $method Case-sensitive method.
169
     *
170
     * @throws InvalidArgumentException for invalid HTTP methods.
171
     *
172
     * @return static
173
     */
174
    public function withMethod(string $method): RequestInterface
175
    {
176
        $new = clone $this;
177
        $new->method = $this->validateHttpMethod(\strtoupper($method));
178
179
        return $new;
180
    }
181
182
    /**
183
     * Retrieves the URI instance.
184
     *
185
     * This method MUST return a UriInterface instance.
186
     *
187
     * @link http://tools.ietf.org/html/rfc3986#section-4.3
188
     *
189
     * @return UriInterface Returns a UriInterface instance
190
     *                      representing the URI of the request.
191
     */
192 7
    public function getUri(): UriInterface
193
    {
194 7
        return $this->uri;
195
    }
196
197
    /**
198
     * Returns an instance with the provided URI.
199
     *
200
     * This method MUST update the Host header of the returned request by
201
     * default if the URI contains a host component. If the URI does not
202
     * contain a host component, any pre-existing Host header MUST be carried
203
     * over to the returned request.
204
     *
205
     * You can opt-in to preserving the original state of the Host header by
206
     * setting `$preserveHost` to `true`. When `$preserveHost` is set to
207
     * `true`, this method interacts with the Host header in the following ways:
208
     *
209
     * - If the Host header is missing or empty, and the new URI contains
210
     *   a host component, this method MUST update the Host header in the returned
211
     *   request.
212
     * - If the Host header is missing or empty, and the new URI does not contain a
213
     *   host component, this method MUST NOT update the Host header in the returned
214
     *   request.
215
     * - If a Host header is present and non-empty, this method MUST NOT update
216
     *   the Host header in the returned request.
217
     *
218
     * This method MUST be implemented in such a way as to retain the
219
     * immutability of the message, and MUST return an instance that has the
220
     * new UriInterface instance.
221
     *
222
     * @link http://tools.ietf.org/html/rfc3986#section-4.3
223
     *
224
     * @param UriInterface $uri          New request URI to use.
225
     * @param bool         $preserveHost Preserve the original state of the Host header.
226
     *
227
     * @return static
228
     */
229 7
    public function withUri(UriInterface $uri, bool $preserveHost = false): RequestInterface
230
    {
231 7
        $new = clone $this;
232 7
        $new->uri = $uri;
233
234 7
        if ($preserveHost && $this->hasHeader('Host')) {
235 1
            return $new;
236
        }
237
238 6
        if (empty($uri->getHost())) {
239 2
            return $new;
240
        }
241
242 4
        $host = $uri->getHost();
243 4
        $port = $uri->getPort();
244
245
        //exclude standard ports from host
246 4
        if (!\in_array($port, [80, 443])) {
247 1
            $host .= ':' . $uri->getPort();
248
        }
249
250 4
        $new = $new->withoutHeader('host');
251 4
        $new->headers['Host'] = [$host];
252
253 4
        return $new;
254
    }
255
}
256