Passed
Push — master ( 4441db...10719f )
by Caen
02:58 queued 12s
created

HydePage::files()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Hyde\Framework\Concerns;
4
5
use Hyde\Framework\Actions\SourceFileParser;
6
use Hyde\Framework\Contracts\CompilableContract;
7
use Hyde\Framework\Contracts\FrontMatter\PageSchema;
8
use Hyde\Framework\Contracts\RouteContract;
9
use Hyde\Framework\Foundation\PageCollection;
10
use Hyde\Framework\Hyde;
11
use Hyde\Framework\Models\FrontMatter;
12
use Hyde\Framework\Models\Metadata\Metadata;
13
use Hyde\Framework\Models\Route;
14
use Hyde\Framework\Services\DiscoveryService;
15
16
/**
17
 * To ensure compatibility with the Hyde Framework, all Page Models should extend this class.
18
 * Markdown-based Pages can extend the AbstractMarkdownPage class to get relevant helpers.
19
 *
20
 * Unlike other frameworks, in general you don't instantiate pages yourself in Hyde,
21
 * instead, the page models acts as blueprints defining information for Hyde to
22
 * know how to parse a file, and what data around it should be generated.
23
 *
24
 * To create a parsed file instance, you'd typically just create a source file,
25
 * and you can then access the parsed file from the HydeKernel's page index.
26
 *
27
 * @see \Hyde\Framework\Concerns\AbstractMarkdownPage
28
 * @see \Hyde\Framework\Testing\Feature\HydePageTest
29
 */
30
abstract class HydePage implements CompilableContract, PageSchema
31
{
32
    use ConstructsPageSchemas;
0 ignored issues
show
Bug introduced by
The trait Hyde\Framework\Concerns\ConstructsPageSchemas requires the property $markdown which is not provided by Hyde\Framework\Concerns\HydePage.
Loading history...
33
34
    public static string $sourceDirectory;
35
    public static string $outputDirectory;
36
    public static string $fileExtension;
37
    public static string $template;
38
39
    public string $identifier;
40
    public string $routeKey;
41
42
    public FrontMatter $matter;
43
    public Metadata $metadata;
44
45
    public string $title;
46
    public ?array $navigation = null;
47
    public ?string $canonicalUrl = null;
48
49
    public function __construct(string $identifier = '', FrontMatter|array $matter = [])
50
    {
51
        $this->identifier = $identifier;
52
        $this->routeKey = trim(static::getOutputDirectory().'/'.$this->identifier, '/');
53
54
        $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...
55
        $this->constructPageSchemas();
56
        $this->metadata = new Metadata($this);
57
    }
58
59
    /**
60
     * Get the directory in where source files are stored.
61
     *
62
     * @return string Path relative to the root of the project
63
     */
64
    final public static function getSourceDirectory(): string
65
    {
66
        return unslash(static::$sourceDirectory);
67
    }
68
69
    /**
70
     * Get the output subdirectory to store compiled HTML.
71
     *
72
     * @return string Relative to the site output directory.
73
     */
74
    final public static function getOutputDirectory(): string
75
    {
76
        return unslash(static::$outputDirectory);
77
    }
78
79
    /**
80
     * Get the file extension of the source files.
81
     *
82
     * @return string (e.g. ".md")
83
     */
84
    final public static function getFileExtension(): string
85
    {
86
        return '.'.ltrim(static::$fileExtension, '.');
87
    }
88
89
    /**
90
     * Parse a source file slug into a page model.
91
     *
92
     * @param  string  $slug
93
     * @return static New page model instance for the parsed source file.
94
     *
95
     * @see \Hyde\Framework\Testing\Unit\PageModelParseHelperTest
96
     */
97
    public static function parse(string $slug): HydePage
98
    {
99
        return (new SourceFileParser(static::class, $slug))->get();
100
    }
101
102
    /**
103
     * Get an array of all the source file slugs for the model.
104
     * Essentially an alias of DiscoveryService::getAbstractPageList().
105
     *
106
     * @return array<string>|false
107
     *
108
     * @see \Hyde\Framework\Testing\Unit\PageModelGetAllFilesHelperTest
109
     */
110
    public static function files(): array|false
111
    {
112
        return DiscoveryService::getSourceFileListForModel(static::class);
113
    }
114
115
    /**
116
     * Get a collection of all pages, parsed into page models.
117
     *
118
     * @return \Hyde\Framework\Foundation\PageCollection<\Hyde\Framework\Concerns\HydePage
119
     *
120
     * @since v0.59.0-beta the returned collection is a PageCollection, and now includes the source file path as the array key
121
     * @see \Hyde\Framework\Testing\Unit\PageModelGetHelperTest
122
     */
123
    public static function all(): PageCollection
124
    {
125
        return Hyde::pages()->getPages(static::class);
126
    }
127
128
    /**
129
     * Qualify a page basename into a referenceable file path.
130
     *
131
     * @param  string  $basename  for the page model source file.
132
     * @return string path to the file relative to project root
133
     */
134
    public static function qualifyBasename(string $basename): string
135
    {
136
        return static::getSourceDirectory().'/'.unslash($basename).static::getFileExtension();
137
    }
138
139
    /**
140
     * Get the proper site output path for a page model.
141
     *
142
     * @param  string  $basename  for the page model source file.
143
     * @return string of the output file relative to the site output directory.
144
     *
145
     * @example DocumentationPage::getOutputPath('index') => 'docs/index.html'
146
     */
147
    public static function getOutputLocation(string $basename): string
148
    {
149
        // Using the trim function we ensure we don't have a leading slash when the output directory is the root directory.
150
        return trim(
151
            static::getOutputDirectory().'/'.unslash($basename),
152
            '/'
153
        ).'.html';
154
    }
155
156
    /**
157
     * Get a value from the computed page data, or fallback to the page's front matter, then to the default value.
158
     *
159
     * @return \Hyde\Framework\Models\FrontMatter|mixed
160
     */
161
    public function get(string $key = null, mixed $default = null): mixed
162
    {
163
        if ($key !== null && property_exists($this, $key) && isset($this->$key)) {
164
            return $this->$key;
165
        }
166
167
        return $this->matter($key, $default);
168
    }
169
170
    /**
171
     * Get the front matter object, or a value from within.
172
     *
173
     * @return \Hyde\Framework\Models\FrontMatter|mixed
174
     */
175
    public function matter(string $key = null, mixed $default = null): mixed
176
    {
177
        return $this->matter->get($key, $default);
178
    }
179
180
    /**
181
     * See if a value exists in the computed page data or the front matter.
182
     *
183
     * @param  string  $key
184
     * @param  bool  $strict  When set to true, an additional check if the property is not blank is performed.
185
     * @return bool
186
     */
187
    public function has(string $key, bool $strict = false): bool
188
    {
189
        if ($strict) {
190
            return property_exists($this, $key) || $this->matter->has($key);
191
        }
192
193
        return ! blank($this->get($key));
194
    }
195
196
    /**
197
     * Get the page model's identifier property.
198
     *
199
     * @return string The page's identifier/slug.
200
     */
201
    public function getIdentifier(): string
202
    {
203
        return $this->identifier;
204
    }
205
206
    /**
207
     * Get the path to the source file, relative to the project root.
208
     *
209
     * @return string Path relative to the project root.
210
     */
211
    public function getSourcePath(): string
212
    {
213
        return static::qualifyBasename($this->identifier);
214
    }
215
216
    /**
217
     * Get the path where the compiled page will be saved.
218
     *
219
     * @return string Path relative to the site output directory.
220
     */
221
    public function getOutputPath(): string
222
    {
223
        return $this->getRouteKey().'.html';
224
    }
225
226
    /**
227
     * Get the route key for the page.
228
     *
229
     * The route key is the URI path relative to the site root.
230
     *
231
     * For example, if the compiled page will be saved to _site/docs/index.html,
232
     * then this method will return 'docs/index'. Route keys are used to
233
     * identify pages, similar to how named routes work in Laravel.
234
     *
235
     * @return string URI path relative to the site root.
236
     */
237
    public function getRouteKey(): string
238
    {
239
        return $this->routeKey;
240
    }
241
242
    /**
243
     * Get the route for the page.
244
     *
245
     * @return \Hyde\Framework\Contracts\RouteContract
246
     */
247
    public function getRoute(): RouteContract
248
    {
249
        return new Route($this);
250
    }
251
252
    /**
253
     * Get the page title to display in the <head> section's <title> tag.
254
     *
255
     * @return string Example: "Site Name - Page Title"
256
     */
257
    public function htmlTitle(): string
258
    {
259
        return config('site.name', 'HydePHP').' - '.$this->title;
260
    }
261
262
    /** @inheritDoc */
263
    public function getBladeView(): string
264
    {
265
        return static::$template;
266
    }
267
268
    /**
269
     * Compile the page into static HTML.
270
     *
271
     * @return string The compiled HTML for the page.
272
     */
273
    abstract public function compile(): string;
274
275
    public function renderPageMetadata(): string
276
    {
277
        return $this->metadata->render();
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 navigationMenuTitle(): string
291
    {
292
        return $this->navigation['title'];
293
    }
294
}
295