Uri   B
last analyzed

Complexity

Total Complexity 43

Size/Duplication

Total Lines 382
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 43
eloc 122
dl 0
loc 382
rs 8.96
c 0
b 0
f 0

26 Methods

Rating   Name   Duplication   Size   Complexity  
A withHost() 0 8 1
A withPort() 0 10 1
A getAuthority() 0 18 4
A withPath() 0 10 1
A getPassword() 0 4 1
A fromString() 0 27 6
A withPassword() 0 4 1
A getPath() 0 4 1
A getQuery() 0 4 1
A getHostPort() 0 10 3
A getUsername() 0 4 1
A __clone() 0 3 1
A withUsername() 0 4 1
A getHost() 0 4 1
A withFragment() 0 10 1
A getUserInfo() 0 4 1
A withQuery() 0 10 1
A withScheme() 0 8 1
A getScheme() 0 4 1
A __toString() 0 15 2
A withUserInfo() 0 20 3
A getSchemeHostPort() 0 7 3
A isSecure() 0 4 1
A __construct() 0 23 2
A getFragment() 0 4 1
A getPort() 0 4 2

How to fix   Complexity   

Complex Class

Complex classes like Uri often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Uri, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Valkyrja Framework package.
7
 *
8
 * (c) Melech Mizrachi <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Valkyrja\Http\Message\Uri;
15
16
use Override;
0 ignored issues
show
Bug introduced by
The type Override was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
17
use Valkyrja\Http\Message\Exception\InvalidArgumentException;
18
use Valkyrja\Http\Message\Uri\Contract\Uri as Contract;
19
use Valkyrja\Http\Message\Uri\Enum\Scheme;
20
use Valkyrja\Http\Message\Uri\Exception\InvalidPathException;
21
use Valkyrja\Http\Message\Uri\Exception\InvalidPortException;
22
use Valkyrja\Http\Message\Uri\Exception\InvalidQueryException;
23
24
use function parse_url;
25
use function str_starts_with;
26
use function strtolower;
27
28
/**
29
 * Class Uri.
30
 *
31
 * @author Melech Mizrachi
32
 */
33
class Uri implements Contract
34
{
35
    use UriHelpers;
0 ignored issues
show
Bug introduced by
The trait Valkyrja\Http\Message\Uri\UriHelpers requires the property $value which is not provided by Valkyrja\Http\Message\Uri\Uri.
Loading history...
36
37
    /**
38
     * @var string
39
     */
40
    protected string $userInfo;
41
42
    /**
43
     * The URI as a string.
44
     *
45
     * @var string|null
46
     */
47
    private string|null $uriString = null;
48
49
    /**
50
     * UriImpl constructor.
51
     *
52
     * @param Scheme   $scheme   [optional] The scheme
53
     * @param string   $username [optional] The username
54
     * @param string   $password [optional] The user password
55
     * @param string   $host     [optional] The host
56
     * @param int|null $port     [optional] The port
57
     * @param string   $path     [optional] The path
58
     * @param string   $query    [optional] The query
59
     * @param string   $fragment [optional] The fragment
60
     *
61
     * @throws InvalidPathException
62
     * @throws InvalidPortException
63
     * @throws InvalidQueryException
64
     */
65
    public function __construct(
66
        protected Scheme $scheme = Scheme::EMPTY,
67
        protected string $username = '',
68
        protected string $password = '',
69
        protected string $host = '',
70
        protected int|null $port = null,
71
        protected string $path = '',
72
        protected string $query = '',
73
        protected string $fragment = ''
74
    ) {
75
        $userInfo = $username;
76
77
        if ($password !== '') {
78
            $userInfo .= ':' . $password;
79
        }
80
81
        $this->validatePort($port);
82
83
        $this->userInfo = $this->filterUserInfo($userInfo);
84
        $this->host     = strtolower($host);
85
        $this->path     = $this->filterPath($path);
86
        $this->query    = $this->filterQuery($query);
87
        $this->fragment = $this->filterFragment($fragment);
88
    }
89
90
    /**
91
     * @inheritDoc
92
     */
93
    #[Override]
94
    public static function fromString(string $uri): static
95
    {
96
        if (
97
            $uri !== ''
98
            && ! str_starts_with($uri, '/')
99
            && ! str_starts_with($uri, Scheme::HTTP->value)
100
            && ! str_starts_with($uri, Scheme::HTTPS->value)
101
        ) {
102
            $uri = '//' . $uri;
103
        }
104
105
        $parts = parse_url($uri);
106
107
        if ($parts === false) {
108
            throw new InvalidArgumentException("Invalid uri `$uri` provided");
109
        }
110
111
        return new static(
112
            scheme: static::filterScheme($parts['scheme'] ?? ''),
113
            username: $parts['user'] ?? '',
114
            password: $parts['pass'] ?? '',
115
            host: $parts['host'] ?? '',
116
            port: $parts['port'] ?? null,
117
            path: $parts['path'] ?? '',
118
            query: $parts['query'] ?? '',
119
            fragment: $parts['fragment'] ?? ''
120
        );
121
    }
122
123
    /**
124
     * @inheritDoc
125
     */
126
    #[Override]
127
    public function isSecure(): bool
128
    {
129
        return $this->scheme === Scheme::HTTPS;
130
    }
131
132
    /**
133
     * @inheritDoc
134
     */
135
    #[Override]
136
    public function getScheme(): Scheme
137
    {
138
        return $this->scheme;
139
    }
140
141
    /**
142
     * @inheritDoc
143
     */
144
    #[Override]
145
    public function getAuthority(): string
146
    {
147
        if (empty($this->host)) {
148
            return '';
149
        }
150
151
        $authority = $this->host;
152
153
        if (! empty($this->userInfo)) {
154
            $authority = $this->userInfo . '@' . $authority;
155
        }
156
157
        if (! $this->isStandardPort()) {
158
            $authority .= ':' . ((string) $this->port);
159
        }
160
161
        return $authority;
162
    }
163
164
    /**
165
     * @inheritDoc
166
     */
167
    #[Override]
168
    public function getUsername(): string
169
    {
170
        return $this->username;
171
    }
172
173
    /**
174
     * @inheritDoc
175
     */
176
    #[Override]
177
    public function getPassword(): string
178
    {
179
        return $this->password;
180
    }
181
182
    /**
183
     * @inheritDoc
184
     */
185
    #[Override]
186
    public function getUserInfo(): string
187
    {
188
        return $this->userInfo;
189
    }
190
191
    /**
192
     * @inheritDoc
193
     */
194
    #[Override]
195
    public function getHost(): string
196
    {
197
        return $this->host;
198
    }
199
200
    /**
201
     * @inheritDoc
202
     */
203
    #[Override]
204
    public function getPort(): int|null
205
    {
206
        return $this->isStandardPort() ? null : $this->port;
207
    }
208
209
    /**
210
     * @inheritDoc
211
     */
212
    #[Override]
213
    public function getHostPort(): string
214
    {
215
        $host = $this->host;
216
217
        if ($host !== '' && ($port = $this->port) !== null) {
218
            $host .= ':' . ((string) $port);
219
        }
220
221
        return $host;
222
    }
223
224
    /**
225
     * @inheritDoc
226
     */
227
    #[Override]
228
    public function getSchemeHostPort(): string
229
    {
230
        $hostPort = $this->getHostPort();
231
        $scheme   = $this->scheme;
232
233
        return $hostPort && $scheme !== Scheme::EMPTY ? $scheme->value . '://' . $hostPort : $hostPort;
234
    }
235
236
    /**
237
     * @inheritDoc
238
     */
239
    #[Override]
240
    public function getPath(): string
241
    {
242
        return $this->path;
243
    }
244
245
    /**
246
     * @inheritDoc
247
     */
248
    #[Override]
249
    public function getQuery(): string
250
    {
251
        return $this->query;
252
    }
253
254
    /**
255
     * @inheritDoc
256
     */
257
    #[Override]
258
    public function getFragment(): string
259
    {
260
        return $this->fragment;
261
    }
262
263
    /**
264
     * @inheritDoc
265
     */
266
    #[Override]
267
    public function withScheme(Scheme $scheme): static
268
    {
269
        $new = clone $this;
270
271
        $new->scheme = $scheme;
272
273
        return $new;
274
    }
275
276
    /**
277
     * @inheritDoc
278
     */
279
    #[Override]
280
    public function withUsername(string $username): static
281
    {
282
        return $this->withUserInfo($username, $this->password);
283
    }
284
285
    /**
286
     * @inheritDoc
287
     */
288
    #[Override]
289
    public function withPassword(string $password): static
290
    {
291
        return $this->withUserInfo($this->username, $password);
292
    }
293
294
    /**
295
     * @inheritDoc
296
     */
297
    #[Override]
298
    public function withUserInfo(string $user, string|null $password = null): static
299
    {
300
        $info = $user;
301
302
        if (empty($user)) {
303
            $password = null;
304
        }
305
306
        if ($password !== null) {
307
            $info .= ':' . $password;
308
        }
309
310
        $new = clone $this;
311
312
        $new->userInfo = $info;
313
        $new->username = $user;
314
        $new->password = $password ?? '';
315
316
        return $new;
317
    }
318
319
    /**
320
     * @inheritDoc
321
     */
322
    #[Override]
323
    public function withHost(string $host): static
324
    {
325
        $new = clone $this;
326
327
        $new->host = $host;
328
329
        return $new;
330
    }
331
332
    /**
333
     * @inheritDoc
334
     */
335
    #[Override]
336
    public function withPort(int|null $port = null): static
337
    {
338
        $this->validatePort($port);
339
340
        $new = clone $this;
341
342
        $new->port = $port;
343
344
        return $new;
345
    }
346
347
    /**
348
     * @inheritDoc
349
     */
350
    #[Override]
351
    public function withPath(string $path): static
352
    {
353
        $path = $this->filterPath($path);
354
355
        $new = clone $this;
356
357
        $new->path = $path;
358
359
        return $new;
360
    }
361
362
    /**
363
     * @inheritDoc
364
     */
365
    #[Override]
366
    public function withQuery(string $query): static
367
    {
368
        $query = $this->filterQuery($query);
369
370
        $new = clone $this;
371
372
        $new->query = $query;
373
374
        return $new;
375
    }
376
377
    /**
378
     * @inheritDoc
379
     */
380
    #[Override]
381
    public function withFragment(string $fragment): static
382
    {
383
        $fragment = $this->filterFragment($fragment);
384
385
        $new = clone $this;
386
387
        $new->fragment = $fragment;
388
389
        return $new;
390
    }
391
392
    /**
393
     * @inheritDoc
394
     */
395
    public function __toString(): string
396
    {
397
        if ($this->uriString !== null) {
398
            return $this->uriString;
399
        }
400
401
        $uri = '';
402
403
        $uri = $this->addSchemeToUri($uri);
404
        $uri = $this->addAuthorityToUri($uri);
405
        $uri = $this->addPathToUri($uri);
406
        $uri = $this->addQueryToUri($uri);
407
        $uri = $this->addFragmentToUri($uri);
408
409
        return $this->uriString = $uri;
410
    }
411
412
    public function __clone()
413
    {
414
        $this->uriString = null;
415
    }
416
}
417