Completed
Branch master (59f97a)
by Dominik
04:18 queued 01:52
created

Uri::with()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 18
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 18
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 13
nc 1
nop 1
1
<?php
2
3
namespace Saxulum\HttpMessage;
4
5
use Psr\Http\Message\UriInterface;
6
7
final class Uri implements UriInterface
8
{
9
    /**
10
     * @var string|null
11
     */
12
    private $scheme;
13
14
    /**
15
     * @var string|null
16
     */
17
    private $host;
18
19
    /**
20
     * @var int|null
21
     */
22
    private $port;
23
24
    const PORT_HTTP = 80;
25
    const PORT_HTTPS = 443;
26
27
    /**
28
     * @var string|null
29
     */
30
    private $user;
31
32
    /**
33
     * @var string|null
34
     */
35
    private $password;
36
37
    /**
38
     * @var string|null
39
     */
40
    private $path;
41
42
    /**
43
     * @var string|null
44
     */
45
    private $query;
46
47
    /**
48
     * @var string|null
49
     */
50
    private $fragment;
51
52
    /**
53
     * @var UriInterface|null
54
     */
55
    private $previous;
56
57
    /**
58
     * @param string|null       $scheme
59
     * @param string|null       $host
60
     * @param int|null          $port
61
     * @param string|null       $user
62
     * @param string|null       $password
63
     * @param string|null       $path
64
     * @param string|null       $query
65
     * @param string|null       $fragment
66
     * @param UriInterface|null $previous
67
     */
68
    public function __construct(
69
        string $scheme = null,
70
        string $host = null,
71
        int $port = null,
72
        string $user = null,
73
        string $password = null,
74
        string $path = null,
75
        string $query = null,
76
        string $fragment = null,
77
        UriInterface $previous = null
78
    ) {
79
        $this->scheme = $scheme;
80
        $this->host = $host;
81
        $this->port = $port;
82
        $this->user = $user;
83
        $this->password = $password;
84
        $this->path = $path;
85
        $this->query = $query;
86
        $this->fragment = $fragment;
87
        $this->previous = $previous;
88
    }
89
90
    /**
91
     * @param string            $uri
92
     * @param UriInterface|null $previous
93
     *
94
     * @return UriInterface
95
     *
96
     * @throws \InvalidArgumentException
97
     */
98
    public static function create(string $uri, UriInterface $previous = null)
99
    {
100
        $uriParts = parse_url($uri);
101
        if (false === $uriParts) {
102
            throw new \InvalidArgumentException(sprintf('Invalid uri format for parse_url: %s', $uri));
103
        }
104
105
        return new self(
106
            $uriParts['scheme'] ?? null,
107
            $uriParts['host'] ?? null,
108
            $uriParts['port'] ?? null,
109
            $uriParts['user'] ?? null,
110
            $uriParts['pass'] ?? null,
111
            $uriParts['path'] ?? null,
112
            $uriParts['query'] ?? null,
113
            $uriParts['fragment'] ?? null,
114
            $previous
115
        );
116
    }
117
118
    /**
119
     * {@inheritdoc}
120
     */
121
    public function getScheme(): string
122
    {
123
        return strtolower((string) $this->scheme);
124
    }
125
126
    /**
127
     * {@inheritdoc}
128
     */
129
    public function getAuthority(): string
130
    {
131
        if ('' === $host = $this->getHost()) {
132
            return '';
133
        }
134
135
        $authority = '';
136
137
        if ('' !== $userInfo = $this->getUserInfo()) {
138
            $authority .= $userInfo.'@';
139
        }
140
141
        $authority .= $host;
142
143
        if (null !== $port = $this->getPort()) {
144
            $authority .= ':'.$port;
145
        }
146
147
        return $authority;
148
    }
149
150
    /**
151
     * {@inheritdoc}
152
     */
153
    public function getUserInfo(): string
154
    {
155
        if (null === $this->user) {
156
            return '';
157
        }
158
159
        if (null === $this->password) {
160
            return $this->user;
161
        }
162
163
        return $this->user.':'.$this->password;
164
    }
165
166
    /**
167
     * {@inheritdoc}
168
     */
169
    public function getHost(): string
170
    {
171
        return strtolower((string) $this->host);
172
    }
173
174
    /**
175
     * {@inheritdoc}
176
     */
177
    public function getPort()
178
    {
179
        if (null === $this->port) {
180
            return null;
181
        }
182
183
        if ($this->port === $this->getPortForScheme($this->getScheme())) {
184
            return null;
185
        }
186
187
        return $this->port;
188
    }
189
190
    /**
191
     * {@inheritdoc}
192
     */
193
    public function getPath(): string
194
    {
195
        return (string) $this->path;
196
    }
197
198
    /**
199
     * {@inheritdoc}
200
     */
201
    public function getQuery(): string
202
    {
203
        return (string) $this->query;
204
    }
205
206
    /**
207
     * {@inheritdoc}
208
     */
209
    public function getFragment(): string
210
    {
211
        return (string) $this->fragment;
212
    }
213
214
    /**
215
     * @return UriInterface|null
216
     */
217
    public function getPrevious()
218
    {
219
        return $this->previous;
220
    }
221
222
    /**
223
     * {@inheritdoc}
224
     */
225
    public function withScheme($scheme): self
226
    {
227
        return $this->with(['scheme' => $scheme]);
228
    }
229
230
    /**
231
     * {@inheritdoc}
232
     */
233
    public function withUserInfo($user, $password = null): self
234
    {
235
        return $this->with(['user' => $user, 'password' => $password]);
236
    }
237
238
    /**
239
     * {@inheritdoc}
240
     */
241
    public function withHost($host): self
242
    {
243
        return $this->with(['host' => $host]);
244
    }
245
246
    /**
247
     * {@inheritdoc}
248
     */
249
    public function withPort($port): self
250
    {
251
        return $this->with(['port' => $port]);
252
    }
253
254
    /**
255
     * {@inheritdoc}
256
     */
257
    public function withPath($path): self
258
    {
259
        return $this->with(['path' => $path]);
260
    }
261
262
    /**
263
     * {@inheritdoc}
264
     */
265
    public function withQuery($query): self
266
    {
267
        return $this->with(['query' => $query]);
268
    }
269
270
    /**
271
     * {@inheritdoc}
272
     */
273
    public function withFragment($fragment): self
274
    {
275
        return $this->with(['fragment' => $fragment]);
276
    }
277
278
    /**
279
     * {@inheritdoc}
280
     */
281
    public function __toString(): string
282
    {
283
        $uri = '';
284
285
        if ('' !== $scheme = $this->getScheme()) {
286
            $uri .= $scheme.':';
287
        }
288
289
        if ('' !== $authority = $this->getAuthority()) {
290
            $uri .= '//'.$authority;
291
        }
292
293
        if ('' !== $path = $this->getPath()) {
294
            $uri .= $this->getPathForUri($authority, $path);
295
        }
296
297
        if ('' !== $query = $this->getQuery()) {
298
            $uri .= '?'.$query;
299
        }
300
301
        if ('' !== $fragment = $this->getFragment()) {
302
            $uri .= '#'.$fragment;
303
        }
304
305
        return $uri;
306
    }
307
308
    /**
309
     * @param string $scheme
310
     *
311
     * @return int|null
312
     */
313
    private function getPortForScheme(string $scheme)
314
    {
315
        $constantName = 'PORT_'.strtoupper($scheme);
316
        $reflection = new \ReflectionObject($this);
317
        if ($reflection->hasConstant($constantName)) {
318
            return $reflection->getConstant($constantName);
319
        }
320
321
        return null;
322
    }
323
324
    /**
325
     * @param string $authority
326
     * @param string $path
327
     *
328
     * @return string
329
     */
330
    private function getPathForUri(string $authority, string $path): string
331
    {
332
        if ('' !== $authority) {
333
            return $this->getPathForUriWithAuthority($path);
334
        }
335
336
        return $this->getPathForUriWithoutAuthority($path);
337
    }
338
339
    /**
340
     * @param string $path
341
     *
342
     * @return string
343
     */
344
    private function getPathForUriWithAuthority(string $path)
345
    {
346
        return '/' === $path[0] ? $path : '/'.$path;
347
    }
348
349
    /**
350
     * @param string $path
351
     *
352
     * @return string
353
     */
354
    private function getPathForUriWithoutAuthority(string $path)
355
    {
356
        $pathLength = strlen($path);
357
        for ($i = 0; $i < $pathLength; ++$i) {
358
            if ('/' !== $path[$i]) {
359
                break;
360
            }
361
        }
362
363
        return 0 === $i ? $path : '/'.substr($path, $i);
364
    }
365
366
    /**
367
     * @param array $arguments
368
     *
369
     * @return Uri
370
     */
371
    public function with(array $arguments): self
372
    {
373
        $defaultArguments = [
374
            'scheme' => $this->scheme,
375
            'host' => $this->host,
376
            'port' => $this->port,
377
            'user' => $this->user,
378
            'password' => $this->password,
379
            'path' => $this->path,
380
            'query' => $this->query,
381
            'fragment' => $this->fragment,
382
            'previous' => $this,
383
        ];
384
385
        $arguments = array_replace($defaultArguments, $arguments);
386
387
        return new self(...array_merge(array_values($arguments), [$this]));
0 ignored issues
show
Documentation introduced by
array_merge(array_values...guments), array($this)) is of type array<integer,?,{"0":"th...m\\HttpMessage\\Uri>"}>, but the function expects a null|string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
388
    }
389
}
390