Test Failed
Pull Request — master (#122)
by
unknown
30:03 queued 23:05
created

Url::get()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 4.1755

Importance

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