Completed
Pull Request — master (#1)
by Philippe
04:41
created

ParsedUrl::parse()   A

Complexity

Conditions 5
Paths 10

Size

Total Lines 25
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 5

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 13
c 1
b 0
f 0
dl 0
loc 25
ccs 13
cts 13
cp 1
rs 9.5222
cc 5
nc 10
nop 1
crap 5
1
<?php
2
3
namespace Thinktomorrow\Url;
4
5
use Thinktomorrow\Url\Exceptions\InvalidUrl;
6
7
class ParsedUrl
8
{
9
    /** @var null|string */
10
    private $scheme;
11
12
    /** @var null|string */
13
    private $host;
14
15
    /** @var string|null */
16
    private $port;
17
18
    /** @var null|string */
19
    private $path;
20
21
    /** @var null|string */
22
    private $query;
23
24
    /** @var null|string */
25
    private $hash;
26
27 17
    public function __construct(?string $scheme = null, ?string $host = null, ?string $port = null, ?string $path = null, ?string $query = null, ?string $hash = null)
28
    {
29 17
        $this->scheme = $scheme;
30 17
        $this->host = $host;
31 17
        $this->port = $port;
32 17
        $this->path = $path;
33 17
        $this->query = $query;
34 17
        $this->hash = $hash;
35 17
    }
36
37 18
    public static function fromUrlString(string $url)
38
    {
39 18
        return new static(...array_values(static::parse($url)));
0 ignored issues
show
Bug introduced by
array_values(static::parse($url)) is expanded, but the parameter $scheme of Thinktomorrow\Url\ParsedUrl::__construct() does not expect variable arguments. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

39
        return new static(/** @scrutinizer ignore-type */ ...array_values(static::parse($url)));
Loading history...
40
    }
41
42 11
    public function get(): string
43
    {
44 11
        return $this->reassembleUrl();
45
    }
46
47 6
    public function replaceScheme(string $scheme): self
48
    {
49 6
        return new static(
50 6
            $scheme,
51 6
            $this->host,
52 6
            $this->port,
53 6
            $this->path,
54 6
            $this->query,
55 6
            $this->hash
56
        );
57
    }
58
59 9
    public function replacePath(string $path): self
60
    {
61 9
        return new static(
62 9
            $this->scheme,
63 9
            $this->host,
64 9
            $this->port,
65 9
            $path,
66 9
            $this->query,
67 9
            $this->hash
68
        );
69
    }
70
71 18
    private static function parse(string $url): array
72
    {
73
        // Specific case where we accept double slashes and convert it to a relative url.
74
        // This would otherwise not be able to be parsed.
75 18
        if ($url == '//') {
76 1
            $url = '/';
77
        }
78
79 18
        $parsed = parse_url($url);
80
81 18
        if (false === $parsed) {
82 1
            throw new InvalidUrl('Failed to parse url. Invalid url ['.$url.'] passed as parameter.');
83
        }
84
85
        // If a schemeless url is passed, parse_url will ignore this and strip the first tags
86
        // so we need to explicitly reassemble the 'anonymous scheme' manually
87 17
        $hasAnonymousScheme = (0 === strpos($url, '//') && isset($parsed['host']));
88
89
        return [
90 17
            'scheme' => $parsed['scheme'] ?? ($hasAnonymousScheme ? '//' : null),
91 17
            'host'   => $parsed['host'] ?? null,
92 17
            'port'   => $parsed['port'] ?? null,
93 17
            'path'   => $parsed['path'] ?? null,
94 17
            'query'  => $parsed['query'] ?? null,
95 17
            'hash'   => $parsed['fragment'] ?? null,
96
        ];
97
    }
98
99 11
    private function reassembleUrl(): string
100
    {
101 11
        return  $this->assembleScheme() .
102 11
                $this->host() .
103 11
                ($this->hasPort() ? ':' . $this->port() : '') .
104 11
                $this->path() .
105 11
                ($this->hasQuery() ? '?' . $this->query() : '') .
106 11
                ($this->hasHash() ? '#' . $this->hash() : '');
107
    }
108
109 11
    private function assembleScheme(): string
110
    {
111 11
        if(!$this->hasScheme()) return '';
112
113
        // Anonymous scheme already ends with double slashes
114 10
        if($this->scheme() == '//') return $this->scheme();
115
116 10
        return $this->scheme() .'://';
117
    }
118
119 10
    public function scheme(): ?string
120
    {
121 10
        return $this->scheme;
122
    }
123
124 11
    public function host(): ?string
125
    {
126 11
        return $this->host;
127
    }
128
129
    public function port(): ?string
130
    {
131
        return $this->port;
132
    }
133
134 15
    public function path(): ?string
135
    {
136 15
        return $this->path;
137
    }
138
139 3
    public function query(): ?string
140
    {
141 3
        return $this->query;
142
    }
143
144 1
    public function hash(): ?string
145
    {
146 1
        return $this->hash;
147
    }
148
149 11
    public function hasScheme(): bool
150
    {
151 11
        return !!$this->scheme;
152
    }
153
154 1
    public function hasHost(): bool
155
    {
156 1
        return !!$this->host;
157
    }
158
159 11
    public function hasPort(): bool
160
    {
161 11
        return !!$this->port;
162
    }
163
164 10
    public function hasPath(): bool
165
    {
166 10
        return !!$this->path;
167
    }
168
169 15
    public function hasQuery(): bool
170
    {
171 15
        return !!$this->query;
172
    }
173
174 15
    public function hasHash(): bool
175
    {
176 15
        return !!$this->hash;
177
    }
178
}
179