Passed
Push — master ( c88e19...2e5eaa )
by Caen
03:32 queued 12s
created

HydePage::setFileExtension()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 3
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Hyde\Pages\Concerns;
6
7
use Hyde\Foundation\Facades;
8
use Hyde\Foundation\Kernel\PageCollection;
9
use Hyde\Framework\Actions\SourceFileParser;
10
use Hyde\Framework\Concerns\InteractsWithFrontMatter;
11
use Hyde\Framework\Factories\Concerns\HasFactory;
12
use Hyde\Framework\Features\Metadata\PageMetadataBag;
13
use Hyde\Framework\Features\Navigation\NavigationData;
14
use Hyde\Framework\Services\DiscoveryService;
15
use Hyde\Hyde;
16
use Hyde\Markdown\Contracts\FrontMatter\PageSchema;
17
use Hyde\Markdown\Models\FrontMatter;
18
use Hyde\Support\Models\Route;
19
use Hyde\Support\Models\RouteKey;
20
use function unslash;
21
22
/**
23
 * The base class for all Hyde pages.
24
 *
25
 * To ensure compatibility with the Hyde Framework, all page models should extend this class.
26
 * Markdown-based pages can extend the BaseMarkdownPage class to get relevant helpers.
27
 *
28
 * Unlike other frameworks, in general you don't instantiate pages yourself in Hyde,
29
 * instead, the page models acts as blueprints defining information for Hyde to
30
 * know how to parse a file, and what data around it should be generated.
31
 *
32
 * To create a parsed file instance, you'd typically just create a source file,
33
 * and you can then access the parsed file from the HydeKernel's page index.
34
 * The source files are usually parsed by the SourceFileParser action.
35
 *
36
 * In Blade views, you can always access the current page instance being rendered using the $page variable.
37
 *
38
 * @see \Hyde\Pages\Concerns\BaseMarkdownPage
39
 * @see \Hyde\Framework\Testing\Feature\HydePageTest
40
 */
41
abstract class HydePage implements PageSchema
42
{
43
    use InteractsWithFrontMatter;
44
    use HasFactory;
0 ignored issues
show
Bug introduced by
The trait Hyde\Framework\Factories\Concerns\HasFactory requires the property $markdown which is not provided by Hyde\Pages\Concerns\HydePage.
Loading history...
45
46
    public static string $sourceDirectory;
47
    public static string $outputDirectory;
48
    public static string $fileExtension;
49
    public static string $template;
50
51
    public string $identifier;
52
    public string $routeKey;
53
54
    public FrontMatter $matter;
55
    public PageMetadataBag $metadata;
56
57
    public string $title;
58
    public ?string $canonicalUrl = null;
59
    public ?NavigationData $navigation = null;
60
61
    public static function make(string $identifier = '', FrontMatter|array $matter = []): static
62
    {
63
        return new static($identifier, $matter);
64
    }
65
66
    public function __construct(string $identifier = '', FrontMatter|array $matter = [])
67
    {
68
        $this->identifier = $identifier;
69
        $this->routeKey = RouteKey::fromPage(static::class, $identifier)->get();
70
71
        $this->matter = $matter instanceof FrontMatter ? $matter : new FrontMatter($matter);
0 ignored issues
show
introduced by
$matter is never a sub-type of Hyde\Markdown\Models\FrontMatter.
Loading history...
72
        $this->constructPageSchemas();
73
        $this->metadata = new PageMetadataBag($this);
74
    }
75
76
    // Section: State
77
78
    public static function isDiscoverable(): bool
79
    {
80
        return isset(static::$sourceDirectory, static::$outputDirectory, static::$fileExtension) && filled(static::$sourceDirectory);
81
    }
82
83
    // Section: Query
84
85
    /**
86
     * Get a page instance from the Kernel's page index by its identifier.
87
     *
88
     *
89
     * @throws \Hyde\Framework\Exceptions\FileNotFoundException If the page does not exist.
90
     */
91
    public static function get(string $identifier): HydePage
92
    {
93
        return Hyde::pages()->getPage(static::sourcePath($identifier));
94
    }
95
96
    /**
97
     * Parse a source file into a page model instance.
98
     *
99
     * @param  string  $identifier  The identifier of the page to parse.
100
     * @return static New page model instance for the parsed source file.
101
     *
102
     * @throws \Hyde\Framework\Exceptions\FileNotFoundException If the file does not exist.
103
     */
104
    public static function parse(string $identifier): HydePage
105
    {
106
        return (new SourceFileParser(static::class, $identifier))->get();
107
    }
108
109
    /**
110
     * Get an array of all the source file identifiers for the model.
111
     *
112
     * Essentially an alias of DiscoveryService::getAbstractPageList().
113
     *
114
     * @return array<string>
115
     */
116
    public static function files(): array
117
    {
118
        return DiscoveryService::getSourceFileListForModel(static::class);
119
    }
120
121
    /**
122
     * Get a collection of all pages, parsed into page models.
123
     *
124
     * @return \Hyde\Foundation\Kernel\PageCollection<\Hyde\Pages\Concerns\HydePage>
125
     */
126
    public static function all(): PageCollection
127
    {
128
        return Facades\Pages::getPages(static::class);
0 ignored issues
show
Bug introduced by
The method getPages() does not exist on Hyde\Foundation\Facades\Pages. Since you implemented __callStatic, consider adding a @method annotation. ( Ignorable by Annotation )

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

128
        return Facades\Pages::/** @scrutinizer ignore-call */ getPages(static::class);
Loading history...
129
    }
130
131
    // Section: Filesystem
132
133
    /**
134
     * Get the directory in where source files are stored.
135
     */
136
    public static function sourceDirectory(): string
137
    {
138
        return static::$sourceDirectory ?? Hyde::getSourceRoot();
139
    }
140
141
    /**
142
     * Get the output subdirectory to store compiled HTML.
143
     */
144
    public static function outputDirectory(): string
145
    {
146
        return static::$outputDirectory ?? '';
147
    }
148
149
    /**
150
     * Get the file extension of the source files.
151
     */
152
    public static function fileExtension(): string
153
    {
154
        return static::$fileExtension ?? '';
155
    }
156
157
    /**
158
     * Set the output directory for the HydePage class.
159
     */
160
    public static function setSourceDirectory(string $sourceDirectory): void
161
    {
162
        static::$sourceDirectory = unslash($sourceDirectory);
163
    }
164
165
    /**
166
     * Set the source directory for the HydePage class.
167
     */
168
    public static function setOutputDirectory(string $outputDirectory): void
169
    {
170
        static::$outputDirectory = unslash($outputDirectory);
171
    }
172
173
    /**
174
     * Set the file extension for the HydePage class.
175
     */
176
    public static function setFileExtension(string $fileExtension): void
177
    {
178
        static::$fileExtension = rtrim('.'.ltrim($fileExtension, '.'), '.');
179
    }
180
181
    /**
182
     * Qualify a page identifier into a local file path for the page source file relative to the project root.
183
     */
184
    public static function sourcePath(string $identifier): string
185
    {
186
        return unslash(static::sourceDirectory().'/'.unslash($identifier).static::fileExtension());
187
    }
188
189
    /**
190
     * Qualify a page identifier into a target output file path relative to the _site output directory.
191
     */
192
    public static function outputPath(string $identifier): string
193
    {
194
        return RouteKey::fromPage(static::class, $identifier).'.html';
195
    }
196
197
    /**
198
     * Get an absolute file path to the page's source directory, or a file within it.
199
     */
200
    public static function path(string $path = ''): string
201
    {
202
        return Hyde::path(unslash(static::sourceDirectory().'/'.unslash($path)));
203
    }
204
205
    /**
206
     * Get the route key base for the page model.
207
     */
208
    public static function baseRouteKey(): string
209
    {
210
        return static::outputDirectory();
211
    }
212
213
    /**
214
     * Compile the page into static HTML.
215
     *
216
     * @return string The compiled HTML for the page.
217
     */
218
    abstract public function compile(): string;
219
220
    /**
221
     * Get the path to the instance source file, relative to the project root.
222
     */
223
    public function getSourcePath(): string
224
    {
225
        return unslash(static::sourcePath($this->identifier));
226
    }
227
228
    /**
229
     * Get the path where the compiled page will be saved.
230
     *
231
     * @return string Path relative to the site output directory.
232
     */
233
    public function getOutputPath(): string
234
    {
235
        return unslash(static::outputPath($this->identifier));
236
    }
237
238
    // Section: Routing
239
240
    /**
241
     * Get the route key for the page.
242
     *
243
     * The route key is the URL path relative to the site root.
244
     *
245
     * For example, if the compiled page will be saved to _site/docs/index.html,
246
     * then this method will return 'docs/index'. Route keys are used to
247
     * identify pages, similar to how named routes work in Laravel,
248
     * only that here the name is not just arbitrary,
249
     * but also defines the output location.
250
     *
251
     * @return string The page's route key.
252
     */
253
    public function getRouteKey(): string
254
    {
255
        return $this->routeKey;
256
    }
257
258
    /**
259
     * Get the route for the page.
260
     *
261
     * @return \Hyde\Support\Models\Route The page's route.
262
     */
263
    public function getRoute(): Route
264
    {
265
        return \Hyde\Facades\Route::get($this->getRouteKey()) ?? new Route($this);
266
    }
267
268
    /**
269
     * Format the page instance to a URL path (relative to site root) with support for pretty URLs if enabled.
270
     */
271
    public function getLink(): string
272
    {
273
        return Hyde::formatLink($this->getOutputPath());
274
    }
275
276
    // Section: Getters
277
278
    /**
279
     * Get the page model's identifier property.
280
     *
281
     * The identifier is the part between the source directory and the file extension.
282
     * It may also be known as a 'slug', or previously 'basename'.
283
     *
284
     * For example, the identifier of a source file stored as '_pages/about/contact.md'
285
     * would be 'about/contact', and 'pages/about.md' would simply be 'about'.
286
     *
287
     * @return string The page's identifier.
288
     */
289
    public function getIdentifier(): string
290
    {
291
        return $this->identifier;
292
    }
293
294
    /**
295
     * Get the Blade template for the page.
296
     *
297
     * @return string Blade template/view key.
298
     */
299
    public function getBladeView(): string
300
    {
301
        return static::$template;
302
    }
303
304
    // Section: Accessors
305
306
    /**
307
     * Get the page title to display in HTML tags like <title> and <meta> tags.
308
     */
309
    public function htmlTitle(): string
310
    {
311
        return config('hyde.name', 'HydePHP').' - '.$this->title;
312
    }
313
314
    public function metadata(): PageMetadataBag
315
    {
316
        return $this->metadata;
317
    }
318
319
    public function showInNavigation(): bool
320
    {
321
        return ! $this->navigation['hidden'];
322
    }
323
324
    public function navigationMenuPriority(): int
325
    {
326
        return $this->navigation['priority'];
327
    }
328
329
    public function navigationMenuLabel(): string
330
    {
331
        return $this->navigation['label'];
332
    }
333
334
    public function navigationMenuGroup(): ?string
335
    {
336
        return $this->navigation['group'];
337
    }
338
}
339