Completed
Push — master ( 486b24...7db650 )
by Miguel A.
02:45
created

UrlComposer::resetPath()   A

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
dl 0
loc 6
c 0
b 0
f 0
ccs 0
cts 3
cp 0
rs 9.4285
cc 1
eloc 3
nc 1
nop 0
crap 2
1
<?php
2
3
namespace Retrinko\UrlComposer;
4
5
use Retrinko\UrlComposer\Exceptions\UrlException;
6
7
class UrlComposer
8
{
9
    const SCHEME_HTTP    = 'http';
10
    const PATH_SEPARATOR = '/';
11
12
    /**
13
     * @var string
14
     */
15
    protected $scheme = self::SCHEME_HTTP;
16
    /**
17
     * @var string
18
     */
19
    protected $user = '';
20
    /**
21
     * @var string
22
     */
23
    protected $pass = '';
24
    /**
25
     * @var string
26
     */
27
    protected $host = '';
28
    /**
29
     * @var int
30
     */
31
    protected $port;
32
    /**
33
     * @var array
34
     */
35
    protected $path = [];
36
    /**
37
     * @var array
38
     */
39
    protected $query = [];
40
    /**
41
     * @var string
42
     */
43
    protected $fragment = '';
44
45
    /**
46
     * Url constructor.
47
     *
48
     * @param string $url
49
     *
50
     * @throws UrlException
51
     */
52 12
    public function __construct($url = '')
53
    {
54 12 View Code Duplication
        if ('' != $url && false === filter_var($url, FILTER_VALIDATE_URL))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
55 12
        {
56 2
            throw new UrlException(sprintf('Invalid URL! (%s)', $url));
57
        }
58
59 10
        $this->parseUrlString($url);
60 10
    }
61
62
    /**
63
     * @param string $url
64
     */
65 10
    protected function parseUrlString($url)
66
    {
67
        // Parse URL
68 10
        $scheme = parse_url($url, PHP_URL_SCHEME);
69 10
        if (!is_null($scheme))
70 10
        {
71 7
            $this->scheme = $scheme;
0 ignored issues
show
Documentation Bug introduced by
It seems like $scheme can also be of type false. However, the property $scheme is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
72 7
        }
73
74 10
        $user = parse_url($url, PHP_URL_USER);
75 10
        if (!is_null($user))
76 10
        {
77
            $this->user = $user;
0 ignored issues
show
Documentation Bug introduced by
It seems like $user can also be of type false. However, the property $user is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
78
        }
79
80 10
        $pass = parse_url($url, PHP_URL_PASS);
81 10
        if (!is_null($pass))
82 10
        {
83
            $this->pass = $pass;
0 ignored issues
show
Documentation Bug introduced by
It seems like $pass can also be of type false. However, the property $pass is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
84
        }
85
86 10
        $host = parse_url($url, PHP_URL_HOST);
87 10
        if (!is_null($host))
88 10
        {
89 7
            $this->host = idn_to_utf8($host);
90 7
        }
91
92 10
        $this->port = parse_url($url, PHP_URL_PORT);
0 ignored issues
show
Documentation Bug introduced by
It seems like parse_url($url, PHP_URL_PORT) can also be of type false. However, the property $port is declared as type integer. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
93
94 10
        $pathStr = parse_url($url, PHP_URL_PATH);
95 10
        if (!is_null($pathStr) && self::PATH_SEPARATOR != $pathStr)
96 10
        {
97 4
            $this->path = explode(self::PATH_SEPARATOR, $pathStr);
98 4
        }
99
100 10
        $queryStr = parse_url($url, PHP_URL_QUERY);
101 10
        if (!is_null($queryStr))
102 10
        {
103 1
            parse_str($queryStr, $query);
104 1
            $this->query = $query;
0 ignored issues
show
Documentation Bug introduced by
It seems like $query can be null. However, the property $query is declared as array. Maybe change the type of the property to array|null or add a type check?

Our type inference engine has found an assignment of a scalar value (like a string, an integer or null) to a property which is an array.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.

To type hint that a parameter can be either an array or null, you can set a type hint of array and a default value of null. The PHP interpreter will then accept both an array or null for that parameter.

function aContainsB(array $needle = null, array  $haystack) {
    if (!$needle) {
        return false;
    }

    return array_intersect($haystack, $needle) == $haystack;
}

The function can be called with either null or an array for the parameter $needle but will only accept an array as $haystack.

Loading history...
105 1
        }
106
107 10
        $fragment = parse_url($url, PHP_URL_FRAGMENT);
108 10
        if (!is_null($fragment))
109 10
        {
110 1
            $this->fragment = $fragment;
0 ignored issues
show
Documentation Bug introduced by
It seems like $fragment can also be of type false. However, the property $fragment is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
111 1
        }
112 10
    }
113
114
    /**
115
     * @param string $string
116
     *
117
     * @return $this
118
     * @throws UrlException
119
     */
120 3
    public function addToPath($string)
121
    {
122 3
        if (!is_string($string))
123 3
        {
124 1
            throw new UrlException('Invalid path part! Path part must be an string.');
125
        }
126
127 2
        $string = filter_var($string, FILTER_SANITIZE_ENCODED);
128 2
        if (false === $string)
129 2
        {
130
            throw new UrlException('Invalid URL chunck!');
131
        }
132
133 2
        if ('' == trim($string))
134 2
        {
135 1
            throw new UrlException('Path part can not be empty!');
136
        }
137
138 1
        $this->path[] = $string;
139
140 1
        return $this;
141
    }
142
143
    /**
144
     * @param string $key
145
     * @param string $value
146
     *
147
     * @return $this
148
     * @throws UrlException
149
     */
150 1
    public function addToQuery($key, $value)
151
    {
152 1
        if ('' == trim($key))
153 1
        {
154 1
            throw new UrlException('Query key can not be empty!');
155
        }
156
        $this->query[$key] = $value;
157
158
        return $this;
159
    }
160
161
    /**
162
     * @param $user
163
     * @param $pass
164
     *
165
     * @return $this
166
     */
167
    public function setUserInfo($user, $pass)
168
    {
169
        return $this->setUser($user)->setPass($pass);
170
    }
171
172
    /**
173
     * Reset auth, path, query & fragment
174
     * @return $this
175
     */
176
    public function reset()
177
    {
178
        $this->resetFragment();
179
        $this->resetPath();
180
        $this->resetQuery();
181
        $this->resetUserInfo();
182
183
        return $this;
184
    }
185
186
    /**
187
     * @return $this
188
     */
189
    public function resetFragment()
190
    {
191
        $this->fragment = null;
192
193
        return $this;
194
    }
195
196
    /**
197
     * @return $this
198
     */
199
    public function resetPath()
200
    {
201
        $this->path = [];
202
203
        return $this;
204
    }
205
206
    /**
207
     * @return $this
208
     */
209
    public function resetQuery()
210
    {
211
        $this->query = [];
212
213
        return $this;
214
    }
215
216
    /**
217
     * @return $this
218
     */
219
    public function resetUserInfo()
220
    {
221
        $this->user = null;
222
        $this->pass = null;
223
224
        return $this;
225
    }
226
227
    /**
228
     * @return string
229
     */
230 7
    public function getScheme()
231
    {
232 7
        return $this->scheme;
233
    }
234
235
    /**
236
     * @param string $scheme
237
     *
238
     * @return $this
239
     */
240 1
    public function setScheme($scheme)
241
    {
242 1
        $this->scheme = $scheme;
243
244 1
        return $this;
245
    }
246
247
    /**
248
     * @return string
249
     */
250 7
    public function getUserInfo()
251
    {
252 7
        if (!empty($this->getPass()) && !empty($this->getUser()))
253 7
        {
254 1
            $userInfo = sprintf('%s:%s', $this->getUser(), $this->getPass());
255 1
        }
256 6
        elseif (empty($this->getPass()) && !empty($this->getUser()))
257
        {
258
            $userInfo = $this->getUser();
259
        }
260
        else
261
        {
262 6
            $userInfo = '';
263
        }
264
265 7
        return $userInfo;
266
    }
267
268
    /**
269
     * @return string
270
     */
271 7
    public function getPass()
272
    {
273 7
        return $this->pass;
274
    }
275
276
    /**
277
     * @param string $pass
278
     *
279
     * @return $this
280
     */
281 1
    public function setPass($pass)
282
    {
283 1
        $this->pass = $pass;
284
285 1
        return $this;
286
    }
287
288
    /**
289
     * @return string
290
     */
291 7
    public function getUser()
292
    {
293 7
        return $this->user;
294
    }
295
296
    /**
297
     * @param string $user
298
     *
299
     * @return $this
300
     */
301 1
    public function setUser($user)
302
    {
303 1
        $this->user = $user;
304
305 1
        return $this;
306
    }
307
308
    /**
309
     * @return string
310
     */
311 7
    public function getHost()
312
    {
313 7
        return $this->host;
314
    }
315
316
    /**
317
     * @param string $host
318
     *
319
     * @return $this
320
     */
321 1
    public function setHost($host)
322
    {
323 1
        $this->host = idn_to_utf8($host);
324
325 1
        return $this;
326
    }
327
328
    /**
329
     * @return int
330
     */
331 7
    public function getPort()
332
    {
333 7
        return $this->port;
334
    }
335
336
    /**
337
     * @param int $port
338
     *
339
     * @return $this
340
     */
341 1
    public function setPort($port)
342
    {
343 1
        $this->port = $port;
344
345 1
        return $this;
346
    }
347
348
    /**
349
     * @param bool $asString
350
     *
351
     * @return array|string
352
     */
353 7
    public function getPath($asString = false)
354
    {
355 7
        $path = $this->path;
356 7
        if (true === $asString)
357 7
        {
358 7
            $path = implode(self::PATH_SEPARATOR, $path);
359 7
        }
360
361 7
        return $path;
362
    }
363
364
    /**
365
     * @param array $path
366
     *
367
     * @return $this
368
     */
369 1
    public function setPath(array $path)
370
    {
371 1
        $this->path = $path;
372
373 1
        return $this;
374
    }
375
376
    /**
377
     * @param bool $asString
378
     *
379
     * @return array|string
380
     */
381 7
    public function getQuery($asString = false)
382
    {
383 7
        $query = $this->query;
384 7
        if (true === $asString)
385 7
        {
386 7
            $query = http_build_query($query);
387 7
        }
388
389 7
        return $query;
390
    }
391
392
    /**
393
     * @param array $query Key-value array
394
     *
395
     * @return $this
396
     */
397 1
    public function setQuery(array $query)
398
    {
399 1
        $this->query = $query;
400
401 1
        return $this;
402
    }
403
404
    /**
405
     * @return string
406
     */
407 7
    public function getFragment()
408
    {
409 7
        return $this->fragment;
410
    }
411
412
    /**
413
     * @param string $fragment
414
     *
415
     * @return $this
416
     */
417 1
    public function setFragment($fragment)
418
    {
419 1
        $this->fragment = $fragment;
420
421 1
        return $this;
422
    }
423
424
    /**
425
     * @return string
426
     */
427 7
    protected function composeAuthority()
428
    {
429 7
        $userInfo = $this->getUserInfo();
430 7
        $port = $this->getPort();
431 7
        $host = $this->getHost();
432 7
        $authority = idn_to_ascii($host);
433 7
        if (!empty($userInfo))
434 7
        {
435 1
            $authority = sprintf('%s@%s', $userInfo, $authority);
436 1
        }
437 7
        if (!is_null($port))
438 7
        {
439 1
            $authority = sprintf('%s:%s', $authority, $port);
440 1
        }
441
442 7
        return $authority;
443
    }
444
445
    /**
446
     * @return string
447
     */
448 2
    public function __toString()
449
    {
450
        try
451
        {
452 2
            $url = $this->compose();
453
        }
454 2
        catch (\Exception $e)
455
        {
456 1
            $url = $e->getMessage();
457
        }
458
459 2
        return $url;
460
    }
461
462
    /**
463
     * @return string
464
     * @throws UrlException
465
     */
466 7
    public function compose()
467
    {
468 7
        $url = sprintf('%s://%s', $this->getScheme(), $this->composeAuthority());
469 7
        if (!empty($this->getPath(true)))
470 7
        {
471 3
            $url = sprintf('%s/%s', $url, $this->getPath(true));
472 3
        }
473 7
        if (!empty($this->getQuery(true)))
474 7
        {
475 2
            $url = sprintf('%s?%s', $url, $this->getQuery(true));
476 2
        }
477 7
        if (!empty($this->getFragment()))
478 7
        {
479 2
            $url = sprintf('%s#%s', $url, $this->getFragment());
480 2
        }
481
482 7 View Code Duplication
        if (false === filter_var($url, FILTER_VALIDATE_URL))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
483 7
        {
484 2
            throw new UrlException(sprintf('URL composition error! Please check your data. ' .
485 2
                                           'The composition result is an invalid URL: "%s"',
486 2
                                           $url));
487
        }
488
489 5
        return $url;
490
    }
491
}