Passed
Push — master ( dff5c5...cec494 )
by Caen
03:44 queued 11s
created

HydeKernel::pathToRelative()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 2
eloc 5
nc 2
nop 1
dl 0
loc 7
rs 10
c 2
b 0
f 0
1
<?php
2
3
namespace Hyde\Framework;
4
5
use Composer\InstalledVersions;
6
use Hyde\Framework\Contracts\HydeKernelContract;
7
use Hyde\Framework\Contracts\RouteContract;
8
use Hyde\Framework\Exceptions\BaseUrlNotSetException;
9
use Hyde\Framework\Helpers\Features;
10
use Hyde\Framework\Models\Pages\BladePage;
11
use Hyde\Framework\Models\Pages\DocumentationPage;
12
use Hyde\Framework\Models\Pages\MarkdownPage;
13
use Hyde\Framework\Models\Pages\MarkdownPost;
14
use Hyde\Framework\Services\DiscoveryService;
15
use Illuminate\Support\Facades\View;
16
use Illuminate\Support\Str;
17
use Illuminate\Support\Traits\Macroable;
18
19
/**
20
 * Encapsulates a HydePHP project, providing helpful methods for interacting with it.
21
 *
22
 * @see \Hyde\Framework\Hyde
23
 *
24
 * @author  Caen De Silva <[email protected]>
25
 * @copyright 2022 Caen De Silva
26
 * @license MIT License
27
 *
28
 * @link https://hydephp.com/
29
 */
30
class HydeKernel implements HydeKernelContract
31
{
32
    use Macroable;
33
34
    protected string $basePath;
35
36
    public function __construct(?string $basePath = null)
37
    {
38
        $this->setBasePath($basePath ?? getcwd());
39
    }
40
41
    public static function getInstance(): HydeKernelContract
42
    {
43
        return app(HydeKernelContract::class);
44
    }
45
46
    public static function version(): string
47
    {
48
        return InstalledVersions::getPrettyVersion('hyde/framework') ?: 'unreleased';
49
    }
50
51
    public function getBasePath(): string
52
    {
53
        return $this->basePath;
54
    }
55
56
    public function setBasePath($basePath)
57
    {
58
        $this->basePath = rtrim($basePath, '/\\');
59
    }
60
61
    // HydeHelperFacade
62
63
    public function features(): Features
64
    {
65
        return new Features;
66
    }
67
68
    public function hasFeature(string $feature): bool
69
    {
70
        return Features::enabled($feature);
71
    }
72
73
    public function makeTitle(string $slug): string
74
    {
75
        $alwaysLowercase = ['a', 'an', 'the', 'in', 'on', 'by', 'with', 'of', 'and', 'or', 'but'];
76
77
        return ucfirst(str_ireplace(
0 ignored issues
show
Bug introduced by
It seems like str_ireplace($alwaysLowe...t\Str::headline($slug)) can also be of type array; however, parameter $string of ucfirst() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

77
        return ucfirst(/** @scrutinizer ignore-type */ str_ireplace(
Loading history...
78
            $alwaysLowercase,
79
            $alwaysLowercase,
80
            Str::headline($slug)
81
        ));
82
    }
83
84
    /**
85
     * File helper methods.
86
     *
87
     * If a method uses the name `path` it refers to an internal file path.
88
     * if a method uses the name `link` it refers to a web link used in Blade templates.
89
     */
90
91
    /**
92
     * Get an absolute file path from a supplied relative path.
93
     *
94
     * The function returns the fully qualified path to your site's root directory.
95
     *
96
     * You may also use the function to generate a fully qualified path to a given file
97
     * relative to the project root directory when supplying the path argument.
98
     *
99
     * @param  string  $path
100
     * @return string
101
     */
102
    public function path(string $path = ''): string
103
    {
104
        if (empty($path)) {
105
            return $this->getBasePath();
106
        }
107
108
        $path = unslash($path);
109
110
        return $this->getBasePath().DIRECTORY_SEPARATOR.$path;
111
    }
112
113
    /**
114
     * Works similarly to the path() function, but returns a file in the Framework package.
115
     *
116
     * @param  string  $path
117
     * @return string
118
     */
119
    public function vendorPath(string $path = ''): string
120
    {
121
        return $this->path('vendor/hyde/framework/'.unslash($path));
122
    }
123
124
    /**
125
     * Format a link to an HTML file, allowing for pretty URLs, if enabled.
126
     *
127
     * @see \Hyde\Framework\Testing\Unit\FileHelperPageLinkPrettyUrlTest
128
     */
129
    public function formatHtmlPath(string $destination): string
130
    {
131
        if (config('site.pretty_urls', false) === true) {
132
            if (str_ends_with($destination, '.html')) {
133
                if ($destination === 'index.html') {
134
                    return '/';
135
                }
136
                if ($destination === DocumentationPage::getOutputDirectory().'/index.html') {
137
                    return DocumentationPage::getOutputDirectory().'/';
138
                }
139
140
                return substr($destination, 0, -5);
141
            }
142
        }
143
144
        return $destination;
145
    }
146
147
    /**
148
     * Inject the proper number of `../` before the links in Blade templates.
149
     *
150
     * @param  string  $destination  relative to output directory on compiled site
151
     * @return string
152
     *
153
     * @see \Hyde\Framework\Testing\Unit\FileHelperRelativeLinkTest
154
     */
155
    public function relativeLink(string $destination): string
156
    {
157
        if (str_starts_with($destination, '../')) {
158
            return $destination;
159
        }
160
161
        $nestCount = substr_count($this->currentPage(), '/');
162
        $route = '';
163
        if ($nestCount > 0) {
164
            $route .= str_repeat('../', $nestCount);
165
        }
166
        $route .= $this->formatHtmlPath($destination);
167
168
        return str_replace('//', '/', $route);
169
    }
170
171
    /**
172
     * Get the current page path, or fall back to the root path.
173
     */
174
    public function currentPage(): string
175
    {
176
        return View::shared('currentPage', '');
177
    }
178
179
    /**
180
     * Get the current page route, or fall back to null.
181
     */
182
    public function currentRoute(): ?RouteContract
183
    {
184
        return View::shared('currentRoute');
185
    }
186
187
    /**
188
     * Gets a relative web link to the given image stored in the _site/media folder.
189
     */
190
    public function image(string $name): string
191
    {
192
        if (str_starts_with($name, 'http')) {
193
            return $name;
194
        }
195
196
        return $this->relativeLink('media/'.basename($name));
197
    }
198
199
    /**
200
     * Return a qualified URI path, if SITE_URL is set in .env, else return false.
201
     *
202
     * @deprecated v0.53.0-beta - Use Hyde::url() or Hyde::hasSiteUrl() instead.
203
     *
204
     * @param  string  $path  optional relative path suffix. Omit to return base url.
205
     * @return string|false
206
     */
207
    public function uriPath(string $path = ''): string|false
208
    {
209
        if (config('site.url', false)) {
210
            return rtrim(config('site.url'), '/').'/'.(trim($path, '/') ?? '');
211
        }
212
213
        return false;
214
    }
215
216
    /**
217
     * Check if a site base URL has been set in config (or .env).
218
     */
219
    public function hasSiteUrl(): bool
220
    {
221
        return ! blank(config('site.url'));
222
    }
223
224
    /**
225
     * Return a qualified URI path to the supplied path if a base URL is set.
226
     *
227
     * @param  string  $path  optional relative path suffix. Omit to return base url.
228
     * @param  string|null  $default  optional default value to return if no site url is set.
229
     * @return string
230
     *
231
     * @throws BaseUrlNotSetException If no site URL is set and no default is provided
232
     */
233
    public function url(string $path = '', ?string $default = null): string
234
    {
235
        $path = $this->formatHtmlPath(trim($path, '/'));
236
237
        if ($this->hasSiteUrl()) {
238
            return rtrim(rtrim(config('site.url'), '/').'/'.($path ?? ''), '/');
239
        }
240
241
        if ($default !== null) {
242
            return $default.'/'.($path ?? '');
243
        }
244
245
        throw new BaseUrlNotSetException();
246
    }
247
248
    /**
249
     * Wrapper for the copy function, but allows choosing if files may be overwritten.
250
     *
251
     * @param  string  $from  The source file path.
252
     * @param  string  $to  The destination file path.
253
     * @param  bool  $force  If true, existing files will be overwritten.
254
     * @return bool|int Returns true|false on copy() success|failure, or an error code on failure
255
     */
256
    public function copy(string $from, string $to, bool $force = false): bool|int
257
    {
258
        if (! file_exists($from)) {
259
            return 404;
260
        }
261
262
        if (file_exists($to) && ! $force) {
263
            return 409;
264
        }
265
266
        return copy($from, $to);
267
    }
268
269
    /**
270
     * Fluent file helper methods.
271
     *
272
     * Provides a more fluent way of getting either the absolute path
273
     * to a model's source directory, or an absolute path to a file within it.
274
     *
275
     * These are intended to be used as a dynamic alternative to legacy code
276
     * Hyde::path('_pages/foo') becomes Hyde::getBladePagePath('foo')
277
     */
278
    public function getModelSourcePath(string $model, string $path = ''): string
279
    {
280
        if (empty($path)) {
281
            return $this->path(DiscoveryService::getFilePathForModelClassFiles($model));
282
        }
283
284
        $path = unslash($path);
285
286
        return $this->path(DiscoveryService::getFilePathForModelClassFiles($model).DIRECTORY_SEPARATOR.$path);
287
    }
288
289
    public function getBladePagePath(string $path = ''): string
290
    {
291
        return $this->getModelSourcePath(BladePage::class, $path);
292
    }
293
294
    public function getMarkdownPagePath(string $path = ''): string
295
    {
296
        return $this->getModelSourcePath(MarkdownPage::class, $path);
297
    }
298
299
    public function getMarkdownPostPath(string $path = ''): string
300
    {
301
        return $this->getModelSourcePath(MarkdownPost::class, $path);
302
    }
303
304
    public function getDocumentationPagePath(string $path = ''): string
305
    {
306
        return $this->getModelSourcePath(DocumentationPage::class, $path);
307
    }
308
309
    /**
310
     * Get the absolute path to the compiled site directory, or a file within it.
311
     */
312
    public function getSiteOutputPath(string $path = ''): string
313
    {
314
        if (empty($path)) {
315
            return StaticPageBuilder::$outputPath;
316
        }
317
318
        $path = unslash($path);
319
320
        return StaticPageBuilder::$outputPath.DIRECTORY_SEPARATOR.$path;
321
    }
322
323
    /**
324
     * Decode an absolute path created with a Hyde::path() helper into its relative counterpart.
325
     */
326
    public function pathToRelative(string $path): string
327
    {
328
        return str_starts_with($path, $this->path()) ? unslash(str_replace(
329
            $this->path(),
330
            '',
331
            $path
332
        )) : $path;
333
    }
334
}
335