Completed
Push — master ( 25df78...65ba04 )
by Ben
02:13
created

Url::nonSecure()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Thinktomorrow\Url;
4
5
use Thinktomorrow\Url\Exceptions\InvalidUrl;
6
7
class Url
8
{
9
    private $parsed;
10
    private $root;
11
12
    private $secure;
13
    private $forceScheme = false;
14
15
    /**
16
     * Schemeless url is considered to be an url with a // prepend.
17
     * @var bool
18
     */
19
    private $schemeless = false;
20
    private $absolute = false;
21
22 17
    private function __construct(string $url)
23
    {
24 17
        $this->parse($url);
25 16
    }
26
27 17
    public static function fromString(string $url)
28
    {
29 17
        return new self($url);
30
    }
31
32 3
    public function setCustomRoot(Root $root)
33
    {
34 3
        $this->root = $root;
35
36 3
        return $this;
37
    }
38
39 3
    public function secure()
40
    {
41 3
        return $this->scheme(true);
42
    }
43
44 2
    public function nonSecure()
45
    {
46 2
        return $this->scheme(false);
47
    }
48
49 5
    private function scheme(bool $secure = true)
50
    {
51 5
        $this->forceScheme = true;
52 5
        $this->secure = $secure;
53
54 5
        return $this;
55
    }
56
57 14
    public function get()
58
    {
59 14
        if ($this->root) {
60 3
            if ($this->secure) {
61 1
                $this->root->secure($this->secure);
62
            }
63
64
            // Path is reconstructed. Taken care of possible double slashes
65 3
            $path = str_replace('//', '/', '/'.trim($this->reassembleWithoutRoot(), '/'));
66
67 3
            if ($path == '/') {
68 1
                $path = '';
69
            }
70
71 3
            return $this->root->get().$path;
72
        }
73
74 11
        return $this->reassemble();
75
    }
76
77 1
    public function isAbsolute(): bool
78
    {
79 1
        return $this->absolute;
80
    }
81
82 8
    public function localize(string $localeSegment = null, array $available_locales = [])
83
    {
84 8
        $this->parsed['path'] = str_replace('//', '/',
85 8
            rtrim(
86 8
                '/'.trim($localeSegment.$this->delocalizePath($available_locales), '/'),
87 8
                '/'
88
            )
89
90
        );
91
92 8
        return $this;
93
    }
94
95 8
    private function delocalizePath(array $available_locales)
96
    {
97 8
        if (!isset($this->parsed['path'])) {
98 2
            return;
99
        }
100
101 8
        $path_segments = explode('/', trim($this->parsed['path'], '/'));
102
103
        // Remove the locale segment if present
104 8
        if (in_array($path_segments[0], array_keys($available_locales))) {
105 1
            unset($path_segments[0]);
106
        }
107
108 8
        return '/'.implode('/', $path_segments);
109
    }
110
111 17
    private function parse(string $url)
112
    {
113
        // Sanitize url input a bit to remove double slashes, but do not remove first slashes
114 17
        if ($url == '//') {
115 1
            $url = '/';
116
        }
117
118 17
        $this->parsed = parse_url($url);
119
120 17
        if (false === $this->parsed) {
121 1
            throw new InvalidUrl('Failed to parse url. Invalid url ['.$url.'] passed as parameter.');
122
        }
123
124
        // If a schemeless url is passed, parse_url will ignore this and strip the first tags
125
        // so we keep a reminder to explicitly reassemble the 'anonymous scheme' manually
126 16
        $this->schemeless = (0 === strpos($url, '//') && isset($this->parsed['host']));
127
128 16
        $this->absolute = (!preg_match('~^(#|//|https?://|mailto:|tel:)~', $url))
129 12
                ? filter_var($url, FILTER_VALIDATE_URL) !== false
130 10
                : true;
131 16
    }
132
133 1
    public function __toString(): string
134
    {
135 1
        return $this->get();
136
    }
137
138 11
    private function reassemble(): string
139
    {
140
        return
141 11
            $this->assembleScheme()
142 11
            .((isset($this->parsed['user'])) ? $this->parsed['user'].((isset($this->parsed['pass'])) ? ':'.$this->parsed['pass'] : '').'@' : '')
143 11
            .((isset($this->parsed['host'])) ? $this->parsed['host'] : '')
144 11
            .((isset($this->parsed['port'])) ? ':'.$this->parsed['port'] : '')
145 11
            .((isset($this->parsed['path'])) ? $this->parsed['path'] : '')
146 11
            .((isset($this->parsed['query'])) ? '?'.$this->parsed['query'] : '')
147 11
            .((isset($this->parsed['fragment'])) ? '#'.$this->parsed['fragment'] : '');
148
    }
149
150
    /**
151
     * Construct a full url with the parsed url elements
152
     * resulted from a parse_url() function call.
153
     *
154
     * @return string
155
     */
156 3
    private function reassembleWithoutRoot()
157
    {
158
        /**
159
         * In some rare conditions the path in interpreted as the host when there is no domain.tld format given.
160
         * This is still considered a valid url, be it with only a tld as indication.
161
         */
162 3
        $path = (isset($this->parsed['path']) && $this->parsed['path'] != $this->root->host())
163 3
                    ? $this->parsed['path']
164 3
                    : '';
165
166
        return $path
167 3
            .((isset($this->parsed['query'])) ? '?'.$this->parsed['query'] : '')
168 3
            .((isset($this->parsed['fragment'])) ? '#'.$this->parsed['fragment'] : '');
169
    }
170
171 11
    private function assembleScheme(): string
172
    {
173 11
        $scheme = (isset($this->parsed['scheme']))
174 9
            ? $this->parsed['scheme'] . '://'
175 11
            : ($this->schemeless ? '//' : '');
176
177
        // Convert to secure scheme if needed or vice versa
178 11
        if(!$this->forceScheme){
179 7
            return $scheme;
180
        }
181
182 4
        return $this->secure ? 'https://' : 'http://';
183
    }
184
}
185