Passed
Push — master ( b2acdc...34f243 )
by Caen
03:56 queued 12s
created

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