Passed
Push — master ( e019f1...cbaf1a )
by Caen
03:07 queued 12s
created

HydePage::all()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 1
b 0
f 0
1
<?php
2
3
namespace Hyde\Framework\Concerns;
4
5
use Hyde\Framework\Actions\SourceFileParser;
6
use Hyde\Framework\Concerns\Internal\ConstructsPageSchemas;
7
use Hyde\Framework\Contracts\CompilableContract;
8
use Hyde\Framework\Contracts\FrontMatter\PageSchema;
9
use Hyde\Framework\Foundation\PageCollection;
10
use Hyde\Framework\Hyde;
11
use Hyde\Framework\Models\FrontMatter;
12
use Hyde\Framework\Models\Metadata\MetadataBag;
13
use Hyde\Framework\Models\NavigationData;
14
use Hyde\Framework\Models\Route;
15
use Hyde\Framework\Services\DiscoveryService;
16
use Illuminate\Support\Arr;
17
18
/**
19
 * To ensure compatibility with the Hyde Framework, all page models should extend this class.
20
 * Markdown-based pages can extend the BaseMarkdownPage class to get relevant helpers.
21
 *
22
 * Unlike other frameworks, in general you don't instantiate pages yourself in Hyde,
23
 * instead, the page models acts as blueprints defining information for Hyde to
24
 * know how to parse a file, and what data around it should be generated.
25
 *
26
 * To create a parsed file instance, you'd typically just create a source file,
27
 * and you can then access the parsed file from the HydeKernel's page index.
28
 * The source files are usually parsed by the SourceFileParser action.
29
 *
30
 * @see \Hyde\Framework\Concerns\BaseMarkdownPage
31
 * @see \Hyde\Framework\Testing\Feature\HydePageTest
32
 */
33
abstract class HydePage implements CompilableContract, PageSchema
34
{
35
    use ConstructsPageSchemas;
0 ignored issues
show
Bug introduced by
The trait Hyde\Framework\Concerns\...l\ConstructsPageSchemas requires the property $markdown which is not provided by Hyde\Framework\Concerns\HydePage.
Loading history...
36
    use Internal\GeneratesNavigationData;
37
38
    public static string $sourceDirectory;
39
    public static string $outputDirectory;
40
    public static string $fileExtension;
41
    public static string $template;
42
43
    public string $identifier;
44
    public string $routeKey;
45
46
    public FrontMatter $matter;
47
    public MetadataBag $metadata;
48
49
    public string $title;
50
    public ?string $canonicalUrl = null;
51
    public ?NavigationData $navigation = null;
52
53
    public function __construct(string $identifier = '', FrontMatter|array $matter = [])
54
    {
55
        $this->identifier = $identifier;
56
        $this->routeKey = static::routeKey($identifier);
57
58
        $this->matter = $matter instanceof FrontMatter ? $matter : new FrontMatter($matter);
0 ignored issues
show
introduced by
$matter is never a sub-type of Hyde\Framework\Models\FrontMatter.
Loading history...
59
        $this->constructPageSchemas();
60
        $this->metadata = new MetadataBag($this);
61
    }
62
63
    // Section: Query
64
65
    /**
66
     * Parse a source file into a page model instance.
67
     *
68
     * @param  string  $identifier  The identifier of the page to parse.
69
     * @return static New page model instance for the parsed source file.
70
     */
71
    public static function parse(string $identifier): HydePage
72
    {
73
        return (new SourceFileParser(static::class, $identifier))->get();
74
    }
75
76
    /**
77
     * Get an array of all the source file identifiers for the model.
78
     *
79
     * Essentially an alias of DiscoveryService::getAbstractPageList().
80
     *
81
     * @return array<string>|false
82
     */
83
    public static function files(): array|false
84
    {
85
        return DiscoveryService::getSourceFileListForModel(static::class);
86
    }
87
88
    /**
89
     * Get a collection of all pages, parsed into page models.
90
     *
91
     * @return \Hyde\Framework\Foundation\PageCollection<\Hyde\Framework\Concerns\HydePage
92
     */
93
    public static function all(): PageCollection
94
    {
95
        return Hyde::pages()->getPages(static::class);
96
    }
97
98
    // Section: Filesystem
99
100
    /**
101
     * Get the directory in where source files are stored.
102
     */
103
    final public static function sourceDirectory(): string
104
    {
105
        return unslash(static::$sourceDirectory);
106
    }
107
108
    /**
109
     * Get the output subdirectory to store compiled HTML.
110
     */
111
    final public static function outputDirectory(): string
112
    {
113
        return unslash(static::$outputDirectory);
114
    }
115
116
    /**
117
     * Get the file extension of the source files.
118
     */
119
    final public static function fileExtension(): string
120
    {
121
        return '.'.ltrim(static::$fileExtension, '.');
122
    }
123
124
    /**
125
     * Qualify a page identifier into a local file path for the page source file relative to the project root.
126
     */
127
    public static function sourcePath(string $identifier): string
128
    {
129
        return static::sourceDirectory().'/'.unslash($identifier).static::fileExtension();
130
    }
131
132
    /**
133
     * Qualify a page identifier into a target output file path relative to the _site output directory.
134
     */
135
    public static function outputPath(string $identifier): string
136
    {
137
        return static::routeKey($identifier).'.html';
138
    }
139
140
    /**
141
     * Get the path to the instance source file, relative to the project root.
142
     */
143
    public function getSourcePath(): string
144
    {
145
        return static::sourcePath($this->identifier);
146
    }
147
148
    /**
149
     * Get the path where the compiled page instance will be saved.
150
     */
151
    public function getOutputPath(): string
152
    {
153
        return static::outputPath($this->identifier);
154
    }
155
156
    // Section: Routing
157
158
    /**
159
     * Format a page identifier to a route key.
160
     */
161
    public static function routeKey(string $identifier): string
162
    {
163
        return unslash(static::outputDirectory().'/'.$identifier);
164
    }
165
166
    /**
167
     * Get the route key for the page.
168
     *
169
     * The route key is the URL path relative to the site root.
170
     *
171
     * For example, if the compiled page will be saved to _site/docs/index.html,
172
     * then this method will return 'docs/index'. Route keys are used to
173
     * identify pages, similar to how named routes work in Laravel.
174
     *
175
     * @return string The page's route key.
176
     */
177
    public function getRouteKey(): string
178
    {
179
        return $this->routeKey;
180
    }
181
182
    /**
183
     * Get the route for the page.
184
     *
185
     * @return \Hyde\Framework\Models\Route The page's route.
186
     */
187
    public function getRoute(): Route
188
    {
189
        return new Route($this);
190
    }
191
192
    /**
193
     * Format the page instance to a URL path (relative to site root) with support for pretty URLs if enabled.
194
     */
195
    public function getLink(): string
196
    {
197
        return Hyde::formatLink($this->getOutputPath());
198
    }
199
200
    // Section: Getters
201
202
    /**
203
     * Get the page model's identifier property.
204
     *
205
     * The identifier is the part between the source directory and the file extension.
206
     * It may also be known as a 'slug', or previously 'basename'.
207
     *
208
     * For example, the identifier of a source file stored as '_pages/about/contact.md'
209
     * would be 'about/contact', and 'pages/about.md' would simply be 'about'.
210
     *
211
     * @return string The page's identifier.
212
     */
213
    public function getIdentifier(): string
214
    {
215
        return $this->identifier;
216
    }
217
218
    /**
219
     * Get the Blade template key for the page.
220
     */
221
    public function getBladeView(): string
222
    {
223
        return static::$template;
224
    }
225
226
    // Section: Front Matter
227
228
    /**
229
     * Get a value from the computed page data, or fallback to the page's front matter, then to the default value.
230
     *
231
     * @return \Hyde\Framework\Models\FrontMatter|mixed
232
     */
233
    public function get(string $key = null, mixed $default = null): mixed
234
    {
235
        return Arr::get(array_filter(array_merge(
236
            $this->matter->toArray(),
237
            (array) $this,
238
        )), $key, $default);
239
    }
240
241
    /**
242
     * Get the front matter object, or a value from within.
243
     *
244
     * @return \Hyde\Framework\Models\FrontMatter|mixed
245
     */
246
    public function matter(string $key = null, mixed $default = null): mixed
247
    {
248
        return $this->matter->get($key, $default);
249
    }
250
251
    /**
252
     * See if a value exists in the computed page data or the front matter.
253
     */
254
    public function has(string $key): bool
255
    {
256
        return ! blank($this->get($key));
257
    }
258
259
    // Section: Accessors
260
261
    /**
262
     * Get the page title to display in HTML tags like <title> and <meta> tags.
263
     */
264
    public function htmlTitle(): string
265
    {
266
        return config('site.name', 'HydePHP').' - '.$this->title;
267
    }
268
269
    public function metadata(): MetadataBag
270
    {
271
        return $this->metadata;
272
    }
273
274
    public function showInNavigation(): bool
275
    {
276
        return ! $this->navigation['hidden'];
277
    }
278
279
    public function navigationMenuPriority(): int
280
    {
281
        return $this->navigation['priority'];
282
    }
283
284
    public function navigationMenuLabel(): string
285
    {
286
        return $this->navigation['label'];
287
    }
288
289
    public function navigationMenuGroup(): ?string
290
    {
291
        return $this->navigation['group'];
292
    }
293
}
294