Passed
Push — master ( 28e8ac...943ae1 )
by Caen
03:10 queued 12s
created

HydePage::getRoute()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 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\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: Query
77
78
    /**
79
     * Get a page instance from the Kernel's page index by its identifier.
80
     *
81
     * @param  string  $identifier
82
     * @return \Hyde\Pages\Concerns\HydePage
83
     *
84
     * @throws \Hyde\Framework\Exceptions\FileNotFoundException If the page does not exist.
85
     */
86
    public static function get(string $identifier): HydePage
87
    {
88
        return Hyde::pages()->getPage(static::sourcePath($identifier));
89
    }
90
91
    /**
92
     * Parse a source file into a page model instance.
93
     *
94
     * @param  string  $identifier  The identifier of the page to parse.
95
     * @return static New page model instance for the parsed source file.
96
     *
97
     * @throws \Hyde\Framework\Exceptions\FileNotFoundException If the file does not exist.
98
     */
99
    public static function parse(string $identifier): HydePage
100
    {
101
        return (new SourceFileParser(static::class, $identifier))->get();
102
    }
103
104
    /**
105
     * Get an array of all the source file identifiers for the model.
106
     *
107
     * Essentially an alias of DiscoveryService::getAbstractPageList().
108
     *
109
     * @return array<string>|false
110
     */
111
    public static function files(): array|false
112
    {
113
        return DiscoveryService::getSourceFileListForModel(static::class);
114
    }
115
116
    /**
117
     * Get a collection of all pages, parsed into page models.
118
     *
119
     * @return \Hyde\Foundation\PageCollection<\Hyde\Pages\Concerns\HydePage>
120
     */
121
    public static function all(): PageCollection
122
    {
123
        return Facades\PageCollection::getPages(static::class);
0 ignored issues
show
Bug introduced by
The method getPages() does not exist on Hyde\Foundation\Facades\PageCollection. 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

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