Path::current()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 4
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 9
ccs 5
cts 5
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
 * @package Velox\Frontend
48
 * @since 1.0.0
49
 * @api
50
 *
51
 * @method static string url(string $path = '/')
52
 * @method static string fromTheme(string $path = '/', string $prefix = '')
53
 * @method static string urlFromTheme(string $path = '/')
54
 * @method static string fromAssets(string $path = '/', string $prefix = '')
55
 * @method static string urlFromAssets(string $path = '/')
56
 */
57
final class Path
58
{
59
    /**
60
     * Returns the current path, or compares it with the passed parameter. Note that the path does not contain the query string.
61
     *
62
     * @param string|null $compareTo [optional] Some path on the server.
63
     *
64
     * @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.
65
     */
66 5
    public static function current(?string $compareTo = null)
67
    {
68 5
        $path = strtok(Globals::getServer('REQUEST_URI'), '?');
69
70 5
        if ($compareTo) {
71 4
            return $path === $compareTo;
72
        }
73
74 5
        return $path;
75
    }
76
77
    /**
78
     * Returns the current URL, or compares it with the passed parameter.
79
     *
80
     * @param string|null $compareTo [optional] Some URL on the server.
81
     *
82
     * @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.
83
     */
84 1
    public static function currentUrl(?string $compareTo = null)
85
    {
86 1
        $url = static::resolveUrl((string)static::current());
87
88 1
        if ($compareTo) {
89 1
            return $url === $compareTo;
90
        }
91
92 1
        return $url;
93
    }
94
95
    /**
96
     * Resolves the passed path to the app root path and returns it.
97
     *
98
     * @param string [optional] $path The path from app root.
99
     *
100
     * @return string An absolute path on the server starting from app root.
101
     */
102 1
    public static function resolve(string $path = '/'): string
103
    {
104
        static $root = null;
105
106 1
        if ($root === null) {
107 1
            $root = Config::get('global.paths.root');
108
        }
109
110 1
        $absolutePath = sprintf(
111
            '%s/%s',
112 1
            rtrim($root, '/'),
113 1
            ltrim($path, '/')
114
        );
115
116 1
        $canonicalPath = realpath($absolutePath);
117
118 1
        return $canonicalPath ? $canonicalPath : $absolutePath;
119
    }
120
121
    /**
122
     * Resolves the passed path to the base URL (starting from app root) and returns it.
123
     *
124
     * @param string [optional] $path The path from app root.
125
     *
126
     * @return string An absolute path on the server (public URL) starting from app root.
127
     */
128 8
    public static function resolveUrl(string $path = '/'): string
129
    {
130
        static $url = null;
131
132 8
        if ($url === null) {
133 1
            $url = Config::get('global.baseUrl', vsprintf('%s://%s', [
134 1
                Globals::getServer('HTTPS') === 'on' ? 'https' : 'http',
135 1
                Globals::getServer('HTTP_HOST'),
136
            ]));
137
        }
138
139 8
        return sprintf(
140
            '%s/%s',
141 8
            rtrim($url, '/'),
142 8
            ltrim($path, '/')
143
        );
144
    }
145
146
    /**
147
     * Resolves the passed path to the theme root path and returns it.
148
     *
149
     * @param string [optional] $path The path from theme root.
150
     * @param string [optional] $prefix The prefix to prefix the returned path with (base URL for example).
151
     *
152
     * @return string A relative path starting from app root to the root of the active theme directory.
153
     */
154 3
    public static function resolveFromTheme(string $path = '/', string $prefix = ''): string
155
    {
156
        static $theme = null;
157
158 3
        if ($theme === null) {
159 1
            $theme = str_replace(
160 1
                Config::get('global.paths.root'),
161
                '',
162 1
                Config::get('theme.paths.root')
163
            );
164
        }
165
166 3
        return sprintf(
167
            '%s/%s/%s',
168 3
            rtrim($prefix, '/'),
169 3
            trim($theme, '/'),
170 3
            ltrim($path, '/')
171
        );
172
    }
173
174
    /**
175
     * Resolves the passed path to the base URL (starting from active theme root) and returns it.
176
     *
177
     * @param string [optional] $path The path from theme root.
178
     *
179
     * @return string An absolute path on the server (public URL) starting from active theme root.
180
     */
181 1
    public static function resolveUrlFromTheme(string $path = '/'): string
182
    {
183 1
        return static::resolveFromTheme($path, static::resolveUrl());
184
    }
185
186
    /**
187
     * Resolves the passed path to the assets directory and returns it.
188
     *
189
     * @param string [optional] $path The path from theme root assets root.
190
     * @param string [optional] $prefix The prefix to prefix the returned path with (base URL for example).
191
     *
192
     * @return string A relative path starting from app root to the root of the assets directory of the active theme directory.
193
     */
194 6
    public static function resolveFromAssets(string $path = '/', string $prefix = ''): string
195
    {
196
        static $assets = null;
197
198 6
        if (!$assets) {
199 1
            $assets = str_replace(
200 1
                Config::get('theme.paths.root'),
201
                '',
202 1
                Config::get('theme.paths.assets')
203
            );
204
205 1
            $assets = static::resolveFromTheme($assets);
206
        }
207
208 6
        return sprintf(
209
            '%s/%s/%s',
210 6
            rtrim($prefix, '/'),
211 6
            trim($assets, '/'),
212 6
            ltrim($path, '/')
213
        );
214
    }
215
216
    /**
217
     * Resolves the passed path to the base URL (starting from active theme assets root) and returns it.
218
     *
219
     * @param string [optional] $path The path from theme root assets root.
220
     *
221
     * @return string An absolute path on the server (public URL) starting from active theme root.
222
     */
223 5
    public static function resolveUrlFromAssets(string $path = '/'): string
224
    {
225 5
        return static::resolveFromAssets($path, static::resolveUrl());
226
    }
227
228
    /**
229
     * Returns a normalized path based on OS.
230
     *
231
     * @param string $directory
232
     * @param string $filename
233
     * @param string $extension
234
     *
235
     * @return string
236
     */
237 38
    public static function normalize(string $directory, string $filename, string $extension = ''): string
238
    {
239 38
        $filename = substr($filename, -strlen($extension)) === $extension ? $filename : $filename . $extension;
240 38
        $directory = $directory . '/';
241
242 38
        return preg_replace('/(\/|\\\)+/', DIRECTORY_SEPARATOR, $directory . $filename);
243
    }
244
245
246
    /**
247
     * Aliases `self::resolve*()` with a function of the same name without the "resolve" prefix.
248
     */
249 2
    public static function __callStatic(string $method, array $arguments)
250
    {
251 2
        $class  = static::class;
252 2
        $method = sprintf('resolve%s', ucfirst($method));
253
254 2
        if (!method_exists($class, $method)) {
255 1
            throw new \Exception("Call to undefined method {$class}::{$method}()");
256
        }
257
258 1
        return static::$method(...$arguments);
259
    }
260
261
    /**
262
     * Allows static methods handled by `self::__callStatic()` to be accessible via object operator `->`.
263
     */
264 2
    public function __call(string $method, array $arguments)
265
    {
266 2
        return static::__callStatic($method, $arguments);
267
    }
268
}
269