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

Root::composeScheme()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 1
c 1
b 0
f 0
nc 4
nop 0
dl 0
loc 3
ccs 0
cts 0
cp 0
crap 12
rs 10
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
        $parsed = static::parse($host);
50
51 7
        return new static($parsed['scheme'], $parsed['host'], $parsed['port'], $parsed['anonymousScheme']);
52
    }
53
54 3
    public function get()
55
    {
56 3
        return $this->composeScheme() .
57
                $this->host() .
58
                ( $this->port() ? ':'.$this->port : null );
59 1
    }
60
61 1
    public function valid(): bool
62
    {
63
        return $this->valid;
64 10
    }
65
66
    public function secure(): self
67 10
    {
68 1
        $this->secure = true;
69
        $this->scheme = 'https';
70
71 10
        return $this;
72 10
    }
73 1
74
    private function composeScheme()
75
    {
76
        return $this->scheme() ? $this->scheme().'://' : ($this->anonymousScheme ? '//' : $this->defaultScheme);
77
    }
78 9
79
    public function replaceScheme(string $scheme): self
80 9
    {
81 9
        return new static(
82 7
            $scheme,
83
            $this->host,
84
            $this->port,
85 9
            false,
86 9
            $this->defaultScheme,
87 9
        );
88
    }
89 1
90
    public function defaultScheme(?string $scheme = null): self
91 1
    {
92
        return new static(
93
            $this->scheme,
94 9
            $this->host,
95
            $this->port,
96 9
            $this->anonymousScheme,
97 7
            $scheme
98
        );
99
    }
100 6
101 1
    public function host(): ?string
102 6
    {
103
        return $this->host;
104
    }
105
106
    public function scheme(): ?string
107
    {
108
        return $this->scheme;
109
    }
110
111
    public function port(): ?string
112
    {
113
        return $this->port;
114
    }
115
116
    private static function parse(string $url)
117
    {
118
        if (in_array($url, ['//','/'])){
119
            return [
120
                'scheme'          => null,
121
                'host'            => null,
122
                'port'            => null,
123
                'anonymousScheme' => false,
124
            ];
125
        }
126
127
        $parsed = parse_url($url);
128
129
        if (false === $parsed) {
130
            throw new InvalidUrl('Failed to parse url. Invalid url ['.$url.'] passed as parameter.');
131
        }
132
133
        return [
134
            'scheme'          => $parsed['scheme'] ?? null,
135
            'host'            => static::parseHost($parsed),
136
            'port'            => $parsed['port'] ?? null,
137
            'anonymousScheme' => static::isAnonymousScheme($url),
138
        ];
139
    }
140
141
    public function __toString(): string
142
    {
143
        return $this->get();
144
    }
145
146
    /**
147
     * If an url is passed with anonymous scheme, e.g. //example.com, parse_url will ignore this and
148
     * strip the first tags so we need to explicitly reassemble the 'anonymous scheme' manually
149
     *
150
     * @param string $host
151
     * @return bool
152
     */
153
    private static function isAnonymousScheme(string $host): bool
154
    {
155
        $parsed = parse_url($host);
156
157
        return !isset($parsed['scheme']) && (0 === strpos($host, '//') && isset($parsed['host']));
158
    }
159
160
    private static function parseHost(array $parsed): ?string
161
    {
162
        if (isset($parsed['host'])) {
163
            return $parsed['host'];
164
        }
165
166
        if(!isset($parsed['path'])) return null;
167
168
        // e.g. /foo/bar
169
        if((0 === strpos($parsed['path'], '/'))) return null;
170
171
        // Invalid tld (missing .tld)
172
        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...
173
174
        // e.g. example.com/foo
175
        if( (0 < strpos($parsed['path'], '/')) ) return substr($parsed['path'], 0, strpos($parsed['path'], '/'));
176
177
        // e.g. foo or example.com
178
        return $parsed['path'];
179
    }
180
}
181