Passed
Push — master ( 72ae8d...bde4cd )
by Ben
01:52
created

Url::forceScheme()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 6
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 1
1
<?php
2
3
namespace Thinktomorrow\Url;
4
5
use Thinktomorrow\Url\Exceptions\InvalidUrl;
6
7
class Url
0 ignored issues
show
Coding Style introduced by
Since you have declared the constructor as private, maybe you should also declare the class as final.
Loading history...
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 18
    private function __construct(string $url)
23
    {
24 18
        $this->parse($url);
25 17
    }
26
27 18
    public static function fromString(string $url)
28
    {
29 18
        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 6
    public function scheme(bool $secure = true)
45
    {
46 6
        $this->forceScheme = true;
47 6
        $this->secure = $secure;
48
49 6
        return $this;
50
    }
51
52 15
    public function get()
53
    {
54 15
        if ($this->root) {
55 3
            if ($this->secure) {
56 1
                $this->root->secure($this->secure);
0 ignored issues
show
Unused Code introduced by
The call to Root::secure() has too many arguments starting with $this->secure.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
57
            }
58
59
            // Path is reconstructed. Taken care of possible double slashes
60 3
            $path = str_replace('//', '/', '/'.trim($this->reassembleWithoutRoot(), '/'));
61
62 3
            if ($path == '/') {
63 1
                $path = '';
64
            }
65
66 3
            return $this->root->get().$path;
67
        }
68
69 12
        return $this->reassemble();
70
    }
71
72 1
    public function isAbsolute(): bool
73
    {
74 1
        return $this->absolute;
75
    }
76
77 8
    public function localize(string $localeSegment = null, array $available_locales = [])
78
    {
79 8
        $this->parsed['path'] = str_replace('//', '/',
80 8
            rtrim(
81 8
                '/'.trim($localeSegment.$this->delocalizePath($available_locales), '/'),
82 8
                '/'
83
            )
84
85
        );
86
87 8
        return $this;
88
    }
89
90 8
    private function delocalizePath(array $available_locales)
91
    {
92 8
        if (!isset($this->parsed['path'])) {
93 2
            return;
94
        }
95
96 8
        $path_segments = explode('/', trim($this->parsed['path'], '/'));
97
98
        // Remove the locale segment if present
99 8
        if (in_array($path_segments[0], array_keys($available_locales))) {
100 1
            unset($path_segments[0]);
101
        }
102
103 8
        return '/'.implode('/', $path_segments);
104
    }
105
106 18
    private function parse(string $url)
107
    {
108
        // Sanitize url input a bit to remove double slashes, but do not remove first slashes
109 18
        if ($url == '//') {
110 1
            $url = '/';
111
        }
112
113 18
        $this->parsed = parse_url($url);
114
115 18
        if (false === $this->parsed) {
116 1
            throw new InvalidUrl('Failed to parse url. Invalid url ['.$url.'] passed as parameter.');
117
        }
118
119
        // If a schemeless url is passed, parse_url will ignore this and strip the first tags
120
        // so we keep a reminder to explicitly reassemble the 'anonymous scheme' manually
121 17
        $this->schemeless = (0 === strpos($url, '//') && isset($this->parsed['host']));
122
123 17
        $this->absolute = (!preg_match('~^(#|//|https?://|mailto:|tel:)~', $url))
124 13
                ? filter_var($url, FILTER_VALIDATE_URL) !== false
125 10
                : true;
126 17
    }
127
128 1
    public function __toString(): string
129
    {
130 1
        return $this->get();
131
    }
132
133 12
    private function reassemble(): string
134
    {
135
        return
136 12
            $this->assembleScheme()
137 12
            .((isset($this->parsed['user'])) ? $this->parsed['user'].((isset($this->parsed['pass'])) ? ':'.$this->parsed['pass'] : '').'@' : '')
138 12
            .((isset($this->parsed['host'])) ? $this->parsed['host'] : '')
139 12
            .((isset($this->parsed['port'])) ? ':'.$this->parsed['port'] : '')
140 12
            .((isset($this->parsed['path'])) ? $this->parsed['path'] : '')
141 12
            .((isset($this->parsed['query'])) ? '?'.$this->parsed['query'] : '')
142 12
            .((isset($this->parsed['fragment'])) ? '#'.$this->parsed['fragment'] : '');
143
    }
144
145
    /**
146
     * Construct a full url with the parsed url elements
147
     * resulted from a parse_url() function call.
148
     *
149
     * @return string
150
     */
151 3
    private function reassembleWithoutRoot()
152
    {
153
        /**
154
         * In some rare conditions the path in interpreted as the host when there is no domain.tld format given.
155
         * This is still considered a valid url, be it with only a tld as indication.
156
         */
157 3
        $path = (isset($this->parsed['path']) && $this->parsed['path'] != $this->root->host())
158 3
                    ? $this->parsed['path']
159 3
                    : '';
160
161
        return $path
162 3
            .((isset($this->parsed['query'])) ? '?'.$this->parsed['query'] : '')
163 3
            .((isset($this->parsed['fragment'])) ? '#'.$this->parsed['fragment'] : '');
164
    }
165
166 12
    private function assembleScheme(): string
167
    {
168 12
        $scheme = (isset($this->parsed['scheme']))
169 9
            ? $this->parsed['scheme'] . '://'
170 12
            : ($this->schemeless ? '//' : '');
171
172
        // Convert to secure scheme if needed or vice versa
173 12
        if(!$this->forceScheme){
174 7
            return $scheme;
175
        }
176
177 5
        return $this->secure ? 'https://' : 'http://';
178
    }
179
}
180