Completed
Pull Request — master (#1)
by Ben
02:08
created

Root::replaceScheme()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 6
nc 1
nop 1
dl 0
loc 8
rs 10
c 0
b 0
f 0
ccs 4
cts 4
cp 1
crap 1
1
<?php
2
3
namespace Thinktomorrow\Url;
4
5
use Thinktomorrow\Url\Exceptions\InvalidUrl;
6
7
class Root
8
{
9
    /** @var string|null */
10
    private $scheme;
11
12
    /** @var string|null */
13
    private $host;
14
15
    /** @var string|null */
16
    private $port;
17
18
    /** @var bool */
19 10
    private $anonymousScheme;
20
21 10
    /** @var null|string */
22
    private $defaultScheme;
23 9
24 9
    /** @var bool */
25
    private $secure = false;
26 9
27
    /** @var bool */
28 10
    private $valid = false;
29
30 10
    private function __construct(?string $scheme = null, ?string $host = null, ?string $port = null, bool $anonymousScheme, ?string $defaultScheme = 'http://')
31
    {
32
        $this->scheme = $scheme;
33 9
        $this->host = $host;
34
        $this->port = $port;
35 9
        $this->anonymousScheme = $anonymousScheme;
36 9
        $this->defaultScheme = $defaultScheme;
37
38 9
        if (false !== filter_var($this->get(), FILTER_VALIDATE_URL)) {
39
            $this->valid = true;
40
        }
41 1
42
        if ($this->composeScheme() == 'https://') {
43 1
            $this->secure();
44
        }
45
    }
46 7
47
    public static function fromString(string $host)
48 7
    {
49 7
        return new static(... array_values(static::parse($host)));
50
    }
51 7
52
    public function get()
53
    {
54 3
        return $this->composeScheme() .
55
                $this->host() .
56 3
                ( $this->port() ? ':'.$this->port : null );
57
    }
58
59 1
    public function valid(): bool
60
    {
61 1
        return $this->valid;
62
    }
63
64 10
    public function secure(): self
65
    {
66
        $this->secure = true;
67 10
        $this->scheme = 'https';
68 1
69
        return $this;
70
    }
71 10
72 10
    private function composeScheme()
73 1
    {
74
        return $this->scheme() ? $this->scheme().'://' : ($this->anonymousScheme ? '//' : $this->defaultScheme);
75
    }
76
77
    public function replaceScheme(string $scheme): self
78 9
    {
79
        return new static(
80 9
            $scheme,
81 9
            $this->host,
82 7
            $this->port,
83
            false,
84
            $this->defaultScheme,
85 9
        );
86 9
    }
87 9
88
    public function defaultScheme(?string $scheme = null): self
89 1
    {
90
        return new static(
91 1
            $this->scheme,
92
            $this->host,
93
            $this->port,
94 9
            $this->anonymousScheme,
95
            $scheme
96 9
        );
97 7
    }
98
99
    public function host(): ?string
100 6
    {
101 1
        return $this->host;
102 6
    }
103
104
    public function scheme(): ?string
105
    {
106
        return $this->scheme;
107
    }
108
109
    public function port(): ?string
110
    {
111
        return $this->port;
112
    }
113
114
    private static function parse(string $url)
115
    {
116
        if (in_array($url, ['//','/'])){
117
            return [
118
                'scheme'          => null,
119
                'host'            => null,
120
                'port'            => null,
121
                'anonymousScheme' => false,
122
            ];
123
        }
124
125
        $parsed = parse_url($url);
126
127
        if (false === $parsed) {
128
            throw new InvalidUrl('Failed to parse url. Invalid url ['.$url.'] passed as parameter.');
129
        }
130
131
        return [
132
            'scheme'          => $parsed['scheme'] ?? null,
133
            'host'            => static::parseHost($parsed),
134
            'port'            => $parsed['port'] ?? null,
135
            'anonymousScheme' => static::isAnonymousScheme($url),
136
        ];
137
    }
138
139
    public function __toString(): string
140
    {
141
        return $this->get();
142
    }
143
144
    /**
145
     * If an url is passed with anonymous scheme, e.g. //example.com, parse_url will ignore this and
146
     * strip the first tags so we need to explicitly reassemble the 'anonymous scheme' manually
147
     *
148
     * @param string $host
149
     * @return bool
150
     */
151
    private static function isAnonymousScheme(string $host): bool
152
    {
153
        $parsed = parse_url($host);
154
155
        return !isset($parsed['scheme']) && (0 === strpos($host, '//') && isset($parsed['host']));
156
    }
157
158
    private static function parseHost(array $parsed): ?string
159
    {
160
        if (isset($parsed['host'])) {
161
            return $parsed['host'];
162
        }
163
164
        if(!isset($parsed['path'])) return null;
165
166
        // e.g. /foo/bar
167
        if((0 === strpos($parsed['path'], '/'))) return null;
168
169
        // Invalid tld (missing .tld)
170
        if(false == strpos($parsed['path'], '.')) return null;
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing strpos($parsed['path'], '.') of type integer to the boolean false. If you are specifically checking for 0, consider using something more explicit like === 0 instead.
Loading history...
171
172
        // e.g. example.com/foo
173
        if( (0 < strpos($parsed['path'], '/')) ) return substr($parsed['path'], 0, strpos($parsed['path'], '/'));
174
175
        // e.g. foo or example.com
176
        return $parsed['path'];
177
    }
178
}
179