Passed
Branch 2.0 (72e182)
by Philippe
02:18
created

Url   B

Complexity

Total Complexity 39

Size/Duplication

Total Lines 155
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
dl 0
loc 155
ccs 65
cts 65
cp 1
rs 8.2857
c 0
b 0
f 0
wmc 39
lcom 1
cbo 2

12 Methods

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