Passed
Push — master ( bbc3bd...e70b0b )
by Marwan
01:25
created

Path::normalize()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 3
c 1
b 0
f 0
nc 2
nop 3
dl 0
loc 6
ccs 4
cts 4
cp 1
crap 2
rs 10
1
<?php
2
3
/**
4
 * @author Marwan Al-Soltany <[email protected]>
5
 * @copyright Marwan Al-Soltany 2021
6
 * For the full copyright and license information, please view
7
 * the LICENSE file that was distributed with this source code.
8
 */
9
10
declare(strict_types=1);
11
12
namespace MAKS\Velox\Frontend;
13
14
use MAKS\Velox\Backend\Config;
15
use MAKS\Velox\Backend\Globals;
16
17
/**
18
 * A class that serves as a path resolver for different paths/URLs of the app.
19
 *
20
 * Example:
21
 * ```
22
 * // NOTE: all methods that have "resolve" as prefix
23
 * // can also be called without the resolve prefix
24
 * // Path::resolve*() -> Path:*() like Path::resolveUrl() -> Path::url()
25
 *
26
 * // get an absolute path from app root
27
 * $path = Path::resolve('some/path');
28
 *
29
 * // get a public URL from app root
30
 * $url = Path::resolveUrl('some/route');
31
 *
32
 *
33
 * // get a relative path from theme root
34
 * $path = Path::resolveFromTheme('some/file.ext');
35
 *
36
 * // get a public URL from theme root
37
 * $url = Path::resolveUrlFromTheme('some/file.ext');
38
 *
39
 *
40
 * // get a relative path from theme assets root
41
 * $path = Path::resolveFromAssets('some/file.ext');
42
 *
43
 * // get a public URL from theme assets root
44
 * $url = Path::resolveUrlFromAssets('some/file.ext');
45
 * ```
46
 *
47
 * @method static string url(string $path = '/')
48
 * @method static string fromTheme(string $path = '/', string $prefix = '')
49
 * @method static string urlFromTheme(string $path = '/')
50
 * @method static string fromAssets(string $path = '/', string $prefix = '')
51
 * @method static string urlFromAssets(string $path = '/')
52
 *
53
 * @since 1.0.0
54
 * @api
55
 */
56
final class Path
57
{
58
    /**
59
     * Returns the current path, or compares it with the passed parameter.
60
     *
61
     * @param string|null $compareTo [optional] Some path on the server.
62
     *
63
     * @return string|bool If null is passed, the current path as string. Otherwise the result of comparing the current path with the passed parameter as boolean.
64
     */
65 2
    public static function current(?string $compareTo = null)
66
    {
67 2
        $path = Globals::getServer('REQUEST_URI');
68
69 2
        if ($compareTo) {
70 1
            return $path === $compareTo;
71
        }
72
73 2
        return $path;
74
    }
75
76
    /**
77
     * Returns the current URL, or compares it with the passed parameter.
78
     *
79
     * @param string|null $compareTo [optional] Some URL on the server.
80
     *
81
     * @return string|bool If null is passed, the current URL as string. Otherwise the result of comparing the current URL with the passed parameter as boolean.
82
     */
83 1
    public static function currentUrl(?string $compareTo = null)
84
    {
85 1
        $url = static::resolveUrl((string)static::current());
86
87 1
        if ($compareTo) {
88 1
            return $url === $compareTo;
89
        }
90
91 1
        return $url;
92
    }
93
94
    /**
95
     * Resolves the passed path to the app root path and returns it.
96
     *
97
     * @param string [optional] $path The path from app root.
98
     *
99
     * @return string An absolute path on the server starting from app root.
100
     */
101 1
    public static function resolve(string $path = '/'): string
102
    {
103 1
        static $root = null;
104
105 1
        if ($root === null) {
106 1
            $root = Config::get('global.paths.root');
107
        }
108
109 1
        $absolutePath = sprintf(
110 1
            '%s/%s',
111 1
            rtrim($root, '/'),
112 1
            ltrim($path, '/')
113
        );
114
115 1
        $canonicalPath = realpath($absolutePath);
116
117 1
        return $canonicalPath ? $canonicalPath : $absolutePath;
118
    }
119
120
    /**
121
     * Resolves the passed path to the base URL (starting from app root) and returns it.
122
     *
123
     * @param string [optional] $path The path from app root.
124
     *
125
     * @return string An absolute path on the server (public URL) starting from app root.
126
     */
127 5
    public static function resolveUrl(string $path = '/'): string
128
    {
129 5
        static $url = null;
130
131 5
        if ($url === null) {
132 1
            $url = (Globals::getServer('HTTPS') === 'on' ? 'https' : 'http') . '://' . Globals::getServer('HTTP_HOST');
133
        }
134
135 5
        return sprintf(
136 5
            '%s/%s',
137 5
            rtrim($url, '/'),
138 5
            ltrim($path, '/')
139
        );
140
    }
141
142
    /**
143
     * Resolves the passed path to the theme root path and returns it.
144
     *
145
     * @param string [optional] $path The path from theme root.
146
     * @param string [optional] $prefix The prefix to prefix the returned path with (base URL for example).
147
     *
148
     * @return string A relative path starting from app root to the root of the active theme directory.
149
     */
150 3
    public static function resolveFromTheme(string $path = '/', string $prefix = ''): string
151
    {
152 3
        static $theme = null;
153
154 3
        if ($theme === null) {
155 1
            $theme = str_replace(
156 1
                Config::get('global.paths.root'),
157 1
                '',
158 1
                Config::get('theme.paths.root')
159
            );
160
        }
161
162 3
        return sprintf(
163 3
            '%s/%s/%s',
164 3
            rtrim($prefix, '/'),
165 3
            trim($theme, '/'),
166 3
            ltrim($path, '/')
167
        );
168
    }
169
170
    /**
171
     * Resolves the passed path to the base URL (starting from active theme root) and returns it.
172
     *
173
     * @param string [optional] $path The path from theme root.
174
     *
175
     * @return string An absolute path on the server (public URL) starting from active theme root.
176
     */
177 1
    public static function resolveUrlFromTheme(string $path = '/'): string
178
    {
179 1
        return static::resolveFromTheme($path, static::resolveUrl());
180
    }
181
182
    /**
183
     * Resolves the passed path to the assets directory and returns it.
184
     *
185
     * @param string [optional] $path The path from theme root assets root.
186
     * @param string [optional] $prefix The prefix to prefix the returned path with (base URL for example).
187
     *
188
     * @return string A relative path starting from app root to the root of the assets directory of the active theme directory.
189
     */
190 3
    public static function resolveFromAssets(string $path = '/', string $prefix = ''): string
191
    {
192 3
        static $assets = null;
193
194 3
        if (!$assets) {
195 1
            $assets = str_replace(
196 1
                Config::get('theme.paths.root'),
197 1
                '',
198 1
                Config::get('theme.paths.assets')
199
            );
200
201 1
            $assets = static::resolveFromTheme($assets);
202
        }
203
204 3
        return sprintf(
205 3
            '%s/%s/%s',
206 3
            rtrim($prefix, '/'),
207 3
            trim($assets, '/'),
208 3
            ltrim($path, '/')
209
        );
210
    }
211
212
    /**
213
     * Resolves the passed path to the base URL (starting from active theme assets root) and returns it.
214
     *
215
     * @param string [optional] $path The path from theme root assets root.
216
     *
217
     * @return string An absolute path on the server (public URL) starting from active theme root.
218
     */
219 2
    public static function resolveUrlFromAssets(string $path = '/'): string
220
    {
221 2
        return static::resolveFromAssets($path, static::resolveUrl());
222
    }
223
224
    /**
225
     * Returns a normalized path based on OS.
226
     *
227
     * @param string $directory
228
     * @param string $filename
229
     * @param string $extension
230
     *
231
     * @return string
232
     */
233 9
    public static function normalize(string $directory, string $filename, string $extension = ''): string
234
    {
235 9
        $filename = substr($filename, -strlen($extension)) === $extension ? $filename : $filename . $extension;
236 9
        $directory = $directory . '/';
237
238 9
        return preg_replace('/\/+|\\+/', DIRECTORY_SEPARATOR, $directory . $filename);
239
    }
240
241
242
    /**
243
     * Aliases `self::resolve*()` with a function of the same name without the "resolve" prefix.
244
     */
245 2
    public static function __callStatic(string $method, array $arguments)
246
    {
247 2
        $class  = static::class;
248 2
        $method = sprintf('resolve%s', ucfirst($method));
249
250 2
        if (!method_exists($class, $method)) {
251 1
            throw new \Exception("Call to undefined method {$class}::{$method}()");
252
        }
253
254 1
        return static::$method(...$arguments);
255
    }
256
257
    /**
258
     * Allows static methods handled by self::__callStatic() to be accessible via object operator `->`.
259
     */
260 2
    public function __call(string $method, array $arguments)
261
    {
262 2
        return static::__callStatic($method, $arguments);
263
    }
264
}
265