Completed
Push — master ( 0eceaa...aee3a6 )
by Ben
15:21 queued 05:47
created

Url::reassemble()   F

Complexity

Conditions 14
Paths 1536

Size

Total Lines 22
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 14

Importance

Changes 0
Metric Value
cc 14
eloc 16
nc 1536
nop 0
dl 0
loc 22
ccs 14
cts 14
cp 1
crap 14
rs 3.5228
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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