Passed
Push — master ( 4ffab8...c52681 )
by Anatoly
05:56 queued 03:01
created

Uri   B

Complexity

Total Complexity 44

Size/Duplication

Total Lines 350
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 7
Bugs 0 Features 0
Metric Value
eloc 107
c 7
b 0
f 0
dl 0
loc 350
ccs 110
cts 110
cp 1
rs 8.8798
wmc 44

18 Methods

Rating   Name   Duplication   Size   Complexity  
A getPort() 0 13 5
A getPath() 0 3 1
A withHost() 0 7 1
A withPort() 0 7 1
A withScheme() 0 7 1
A withFragment() 0 7 1
A getQuery() 0 3 1
A getStandardPort() 0 13 3
A getHost() 0 3 1
A withUserInfo() 0 7 1
B __toString() 0 49 10
A getFragment() 0 3 1
A getAuthority() 0 18 4
B __construct() 0 41 9
A getUserInfo() 0 3 1
A getScheme() 0 3 1
A withPath() 0 7 1
A withQuery() 0 7 1

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 declare(strict_types=1);
2
3
/**
4
 * It's free open-source software released under the MIT License.
5
 *
6
 * @author Anatoly Fenric <[email protected]>
7
 * @copyright Copyright (c) 2018, Anatoly Fenric
8
 * @license https://github.com/sunrise-php/uri/blob/master/LICENSE
9
 * @link https://github.com/sunrise-php/uri
10
 */
11
12
namespace Sunrise\Uri;
13
14
/**
15
 * Import classes
16
 */
17
use Psr\Http\Message\UriInterface;
18
use Sunrise\Uri\Component\Scheme;
19
use Sunrise\Uri\Component\UserInfo;
20
use Sunrise\Uri\Component\Host;
21
use Sunrise\Uri\Component\Port;
22
use Sunrise\Uri\Component\Path;
23
use Sunrise\Uri\Component\Query;
24
use Sunrise\Uri\Component\Fragment;
25
26
/**
27
 * Import functions
28
 */
29
use function getservbyname;
30
use function ltrim;
31
use function strncmp;
32
33
/**
34
 * Uniform Resource Identifier
35
 *
36
 * @link https://tools.ietf.org/html/rfc3986
37
 * @link https://www.php-fig.org/psr/psr-7/
38
 */
39
class Uri implements UriInterface
40
{
41
42
    /**
43
     * The URI component "scheme"
44
     *
45
     * @var string
46
     */
47
    protected $scheme = '';
48
49
    /**
50
     * The URI component "userinfo"
51
     *
52
     * @var string
53
     */
54
    protected $userinfo = '';
55
56
    /**
57
     * The URI component "host"
58
     *
59
     * @var string
60
     */
61
    protected $host = '';
62
63
    /**
64
     * The URI component "port"
65
     *
66
     * @var int|null
67
     */
68
    protected $port;
69
70
    /**
71
     * The URI component "path"
72
     *
73
     * @var string
74
     */
75
    protected $path = '';
76
77
    /**
78
     * The URI component "query"
79
     *
80
     * @var string
81
     */
82
    protected $query = '';
83
84
    /**
85
     * The URI component "fragment"
86
     *
87
     * @var string
88
     */
89
    protected $fragment = '';
90
91
    /**
92
     * Constructor of the class
93
     *
94
     * @param mixed $uri
95
     */
96 119
    public function __construct($uri = '')
97
    {
98 119
        if ($uri === '') {
99 74
            return;
100
        }
101
102 45
        $parsedUri = new UriParser($uri);
103
104 44
        $scheme = $parsedUri->getScheme();
105 44
        if (isset($scheme)) {
106 43
            $this->scheme = $scheme->present();
107
        }
108
109 44
        $userinfo = $parsedUri->getUserInfo();
110 44
        if (isset($userinfo)) {
111 37
            $this->userinfo = $userinfo->present();
112
        }
113
114 44
        $host = $parsedUri->getHost();
115 44
        if (isset($host)) {
116 39
            $this->host = $host->present();
117
        }
118
119 44
        $port = $parsedUri->getPort();
120 44
        if (isset($port)) {
121 38
            $this->port = $port->present();
122
        }
123
124 44
        $path = $parsedUri->getPath();
125 44
        if (isset($path)) {
126 41
            $this->path = $path->present();
127
        }
128
129 44
        $query = $parsedUri->getQuery();
130 44
        if (isset($query)) {
131 37
            $this->query = $query->present();
132
        }
133
134 44
        $fragment = $parsedUri->getFragment();
135 44
        if (isset($fragment)) {
136 36
            $this->fragment = $fragment->present();
137
        }
138
    }
139
140
    /**
141
     * {@inheritdoc}
142
     */
143 13
    public function withScheme($scheme) : UriInterface
144
    {
145 13
        $clone = clone $this;
146 13
        $component = new Scheme($scheme);
147 3
        $clone->scheme = $component->present();
148
149 3
        return $clone;
150
    }
151
152
    /**
153
     * {@inheritdoc}
154
     *
155
     * @psalm-suppress ParamNameMismatch
156
     */
157 22
    public function withUserInfo($user, $pass = null) : UriInterface
158
    {
159 22
        $clone = clone $this;
160 22
        $component = new UserInfo($user, $pass);
161 5
        $clone->userinfo = $component->present();
162
163 5
        return $clone;
164
    }
165
166
    /**
167
     * {@inheritdoc}
168
     */
169 14
    public function withHost($host) : UriInterface
170
    {
171 14
        $clone = clone $this;
172 14
        $component = new Host($host);
173 5
        $clone->host = $component->present();
174
175 5
        return $clone;
176
    }
177
178
    /**
179
     * {@inheritdoc}
180
     */
181 14
    public function withPort($port) : UriInterface
182
    {
183 14
        $clone = clone $this;
184 14
        $component = new Port($port);
185 3
        $clone->port = $component->present();
186
187 3
        return $clone;
188
    }
189
190
    /**
191
     * {@inheritdoc}
192
     */
193 13
    public function withPath($path) : UriInterface
194
    {
195 13
        $clone = clone $this;
196 13
        $component = new Path($path);
197 4
        $clone->path = $component->present();
198
199 4
        return $clone;
200
    }
201
202
    /**
203
     * {@inheritdoc}
204
     */
205 12
    public function withQuery($query) : UriInterface
206
    {
207 12
        $clone = clone $this;
208 12
        $component = new Query($query);
209 3
        $clone->query = $component->present();
210
211 3
        return $clone;
212
    }
213
214
    /**
215
     * {@inheritdoc}
216
     */
217 12
    public function withFragment($fragment) : UriInterface
218
    {
219 12
        $clone = clone $this;
220 12
        $component = new Fragment($fragment);
221 3
        $clone->fragment = $component->present();
222
223 3
        return $clone;
224
    }
225
226
    /**
227
     * {@inheritdoc}
228
     */
229 11
    public function getScheme() : string
230
    {
231 11
        return $this->scheme;
232
    }
233
234
    /**
235
     * {@inheritdoc}
236
     */
237 5
    public function getUserInfo() : string
238
    {
239 5
        return $this->userinfo;
240
    }
241
242
    /**
243
     * {@inheritdoc}
244
     */
245 5
    public function getHost() : string
246
    {
247 5
        return $this->host;
248
    }
249
250
    /**
251
     * {@inheritdoc}
252
     */
253 7
    public function getPort() : ?int
254
    {
255
        // The 80 is the default port number for the HTTP protocol.
256 7
        if ($this->port === 80 && $this->scheme === 'http') {
257 1
            return null;
258
        }
259
260
        // The 443 is the default port number for the HTTPS protocol.
261 7
        if ($this->port === 443 && $this->scheme === 'https') {
262 1
            return null;
263
        }
264
265 7
        return $this->port;
266
    }
267
268
    /**
269
     * Gets the standard port number associated with the URI scheme
270
     *
271
     * @return int|null
272
     *
273
     * @codeCoverageIgnore
274
     */
275
    public function getStandardPort() : ?int
276
    {
277
        $servicePort = getservbyname($this->scheme, 'tcp');
278
        if ($servicePort !== false) {
279
            return $servicePort;
280
        }
281
282
        $servicePort = getservbyname($this->scheme, 'udp');
283
        if ($servicePort !== false) {
284
            return $servicePort;
285
        }
286
287
        return null;
288
    }
289
290
    /**
291
     * {@inheritdoc}
292
     */
293 13
    public function getPath() : string
294
    {
295 13
        return $this->path;
296
    }
297
298
    /**
299
     * {@inheritdoc}
300
     */
301 8
    public function getQuery() : string
302
    {
303 8
        return $this->query;
304
    }
305
306
    /**
307
     * {@inheritdoc}
308
     */
309 7
    public function getFragment() : string
310
    {
311 7
        return $this->fragment;
312
    }
313
314
    /**
315
     * {@inheritdoc}
316
     */
317 4
    public function getAuthority() : string
318
    {
319
        // Host is the basic subcomponent.
320 4
        if ($this->host === '') {
321 2
            return '';
322
        }
323
324 4
        $authority = $this->host;
325 4
        if ($this->userinfo !== '') {
326 3
            $authority = $this->userinfo . '@' . $authority;
327
        }
328
329 4
        $port = $this->getPort();
330 4
        if ($port !== null) {
331 3
            $authority = $authority . ':' . $port;
332
        }
333
334 4
        return $authority;
335
    }
336
337
    /**
338
     * {@inheritdoc}
339
     */
340 3
    public function __toString()
341
    {
342 3
        $uri = '';
343
344 3
        $scheme = $this->getScheme();
345 3
        if ($scheme !== '') {
346 3
            $uri .= $scheme . ':';
347
        }
348
349 3
        $authority = $this->getAuthority();
350 3
        if ($authority !== '') {
351 3
            $uri .= '//' . $authority;
352
        }
353
354 3
        $path = $this->getPath();
355 3
        if ($path !== '') {
356
            // https://github.com/sunrise-php/uri/issues/31
357
            // https://datatracker.ietf.org/doc/html/rfc3986#section-3.3
358
            //
359
            // If a URI contains an authority component,
360
            // then the path component must either be empty
361
            // or begin with a slash ("/") character.
362 3
            if ($authority !== '' && strncmp($path, '/', 1) !== 0) {
363 1
                $path = '/' . $path;
364
            }
365
366
            // https://github.com/sunrise-php/uri/issues/31
367
            // https://datatracker.ietf.org/doc/html/rfc3986#section-3.3
368
            //
369
            // If a URI does not contain an authority component,
370
            // then the path cannot begin with two slash characters ("//").
371 3
            if ($authority === '' && strncmp($path, '//', 2) === 0) {
372 1
                $path = '/' . ltrim($path, '/');
373
            }
374
375 3
            $uri .= $path;
376
        }
377
378 3
        $query = $this->getQuery();
379 3
        if ($query !== '') {
380 1
            $uri .= '?' . $query;
381
        }
382
383 3
        $fragment = $this->getFragment();
384 3
        if ($fragment !== '') {
385 1
            $uri .= '#' . $fragment;
386
        }
387
388 3
        return $uri;
389
    }
390
}
391