Passed
Push — master ( 55b4f9...a3ca0b )
by Caen
03:44 queued 13s
created

HydeKernel::url()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 5
nc 3
nop 2
dl 0
loc 11
rs 10
c 0
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\Helpers\Features;
9
use Hyde\Framework\Models\Pages\BladePage;
10
use Hyde\Framework\Models\Pages\DocumentationPage;
11
use Hyde\Framework\Models\Pages\MarkdownPage;
12
use Hyde\Framework\Models\Pages\MarkdownPost;
13
use Hyde\Framework\Services\DiscoveryService;
14
use Illuminate\Support\Facades\View;
15
use Illuminate\Support\Str;
16
use Illuminate\Support\Traits\Macroable;
17
18
/**
19
 * Encapsulates a HydePHP project, providing helpful methods for interacting with it.
20
 *
21
 * @see \Hyde\Framework\Hyde
22
 *
23
 * @author  Caen De Silva <[email protected]>
24
 * @copyright 2022 Caen De Silva
25
 * @license MIT License
26
 *
27
 * @link https://hydephp.com/
28
 */
29
class HydeKernel implements HydeKernelContract
30
{
31
    use Macroable;
1 ignored issue
show
Bug introduced by
The trait Illuminate\Support\Traits\Macroable requires the property $name which is not provided by Hyde\Framework\HydeKernel.
Loading history...
32
33
    protected string $basePath;
34
35
    public function __construct(?string $basePath = null)
36
    {
37
        $this->setBasePath($basePath ?? getcwd());
38
    }
39
40
    public static function getInstance(): HydeKernelContract
41
    {
42
        return app(HydeKernelContract::class);
43
    }
44
45
    public static function version(): string
46
    {
47
        return InstalledVersions::getPrettyVersion('hyde/framework') ?: 'unreleased';
48
    }
49
50
    public function getBasePath(): string
51
    {
52
        return $this->basePath;
53
    }
54
55
    public function setBasePath($basePath)
56
    {
57
        $this->basePath = rtrim($basePath, '/\\');
58
    }
59
60
    // HydeHelperFacade
61
62
    public function features(): Features
63
    {
64
        return new Features;
65
    }
66
67
    public function hasFeature(string $feature): bool
68
    {
69
        return Features::enabled($feature);
70
    }
71
72
    public function makeTitle(string $slug): string
73
    {
74
        $alwaysLowercase = ['a', 'an', 'the', 'in', 'on', 'by', 'with', 'of', 'and', 'or', 'but'];
75
76
        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

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