Passed
Push — master ( 8a9b32...e03915 )
by Caen
03:03 queued 12s
created

HydePage::outputDirectory()   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
 * The source files are usually parsed by the SourceFileParser action.
27
 *
28
 * @see \Hyde\Framework\Concerns\AbstractMarkdownPage
29
 * @see \Hyde\Framework\Testing\Feature\HydePageTest
30
 */
31
abstract class HydePage implements CompilableContract, PageSchema
32
{
33
    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...
34
35
    public static string $sourceDirectory;
36
    public static string $outputDirectory;
37
    public static string $fileExtension;
38
    public static string $template;
39
40
    public string $identifier;
41
    public string $routeKey;
42
43
    public FrontMatter $matter;
44
    public Metadata $metadata;
45
46
    public string $title;
47
    public ?array $navigation = null;
48
    public ?string $canonicalUrl = null;
49
50
    public function __construct(string $identifier = '', FrontMatter|array $matter = [])
51
    {
52
        $this->identifier = $identifier;
53
        $this->routeKey = static::routeKey($identifier);
54
55
        $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...
56
        $this->constructPageSchemas();
57
        $this->metadata = new Metadata($this);
58
    }
59
60
    // Section: Query
61
62
    /**
63
     * Parse a source file into a page model instance.
64
     *
65
     * @param  string  $identifier  The identifier of the page to parse.
66
     * @return static New page model instance for the parsed source file.
67
     */
68
    public static function parse(string $identifier): HydePage
69
    {
70
        return (new SourceFileParser(static::class, $identifier))->get();
71
    }
72
73
    /**
74
     * Get an array of all the source file identifiers for the model.
75
     *
76
     * Essentially an alias of DiscoveryService::getAbstractPageList().
77
     *
78
     * @return array<string>|false
79
     */
80
    public static function files(): array|false
81
    {
82
        return DiscoveryService::getSourceFileListForModel(static::class);
83
    }
84
85
    /**
86
     * Get a collection of all pages, parsed into page models.
87
     *
88
     * @return \Hyde\Framework\Foundation\PageCollection<\Hyde\Framework\Concerns\HydePage
89
     */
90
    public static function all(): PageCollection
91
    {
92
        return Hyde::pages()->getPages(static::class);
93
    }
94
95
    // Section: Filesystem
96
97
    /**
98
     * Get the directory in where source files are stored.
99
     */
100
    final public static function sourceDirectory(): string
101
    {
102
        return unslash(static::$sourceDirectory);
103
    }
104
105
    /**
106
     * Get the output subdirectory to store compiled HTML.
107
     */
108
    final public static function outputDirectory(): string
109
    {
110
        return unslash(static::$outputDirectory);
111
    }
112
113
    /**
114
     * Get the file extension of the source files.
115
     */
116
    final public static function fileExtension(): string
117
    {
118
        return '.'.ltrim(static::$fileExtension, '.');
119
    }
120
121
    /**
122
     * Qualify a page identifier into a referenceable local file path.
123
     */
124
    public static function sourcePath(string $identifier): string
125
    {
126
        return static::sourceDirectory().'/'.unslash($identifier).static::fileExtension();
127
    }
128
129
    /**
130
     * Get the proper site output path for a page model.
131
     */
132
    public static function outputPath(string $identifier): string
133
    {
134
        return static::routeKey($identifier).'.html';
135
    }
136
137
    /**
138
     * Get the path to the source file, relative to the project root.
139
     * In other words, qualify the identifier of the page instance.
140
     */
141
    public function getSourcePath(): string
142
    {
143
        return static::sourcePath($this->identifier);
144
    }
145
146
    /**
147
     * Get the path where the compiled page instance will be saved.
148
     */
149
    public function getOutputPath(): string
150
    {
151
        return static::outputPath($this->identifier);
152
    }
153
154
    // Section: Routing
155
156
    /**
157
     * Format a page identifier to a route key.
158
     */
159
    public static function routeKey(string $identifier): string
160
    {
161
        return unslash(static::outputDirectory().'/'.$identifier);
162
    }
163
164
    /**
165
     * Get the route key for the page.
166
     *
167
     * The route key is the URI path relative to the site root.
168
     *
169
     * For example, if the compiled page will be saved to _site/docs/index.html,
170
     * then this method will return 'docs/index'. Route keys are used to
171
     * identify pages, similar to how named routes work in Laravel.
172
     *
173
     * @return string The page's route key.
174
     */
175
    public function getRouteKey(): string
176
    {
177
        return $this->routeKey;
178
    }
179
180
    /**
181
     * Get the route for the page.
182
     *
183
     * @return RouteContract The page's route.
184
     */
185
    public function getRoute(): RouteContract
186
    {
187
        return new Route($this);
188
    }
189
190
    // Section: Getters
191
192
    /**
193
     * Get the page model's identifier property.
194
     *
195
     * The identifier is the part between the source directory and the file extension.
196
     * It may also be known as a 'slug', or previously 'basename'.
197
     *
198
     * For example, the identifier of a source file stored as '_pages/about/contact.md'
199
     * would be 'about/contact', and 'pages/about.md' would simply be 'about'.
200
     *
201
     * @return string The page's identifier.
202
     */
203
    public function getIdentifier(): string
204
    {
205
        return $this->identifier;
206
    }
207
208
    /**
209
     * Get the Blade template key for the page.
210
     */
211
    public function getBladeView(): string
212
    {
213
        return static::$template;
214
    }
215
216
    // Section: Front Matter
217
218
    /**
219
     * Get a value from the computed page data, or fallback to the page's front matter, then to the default value.
220
     *
221
     * @return \Hyde\Framework\Models\FrontMatter|mixed
222
     */
223
    public function get(string $key = null, mixed $default = null): mixed
224
    {
225
        if ($key !== null && property_exists($this, $key) && isset($this->$key)) {
226
            return $this->$key;
227
        }
228
229
        return $this->matter($key, $default);
230
    }
231
232
    /**
233
     * Get the front matter object, or a value from within.
234
     *
235
     * @return \Hyde\Framework\Models\FrontMatter|mixed
236
     */
237
    public function matter(string $key = null, mixed $default = null): mixed
238
    {
239
        return $this->matter->get($key, $default);
240
    }
241
242
    /**
243
     * See if a value exists in the computed page data or the front matter.
244
     */
245
    public function has(string $key): bool
246
    {
247
        return ! blank($this->get($key));
248
    }
249
250
    // Section: Accessors
251
252
    /**
253
     * Get the page title to display in HTML tags like <title> and <meta> tags.
254
     */
255
    public function htmlTitle(): string
256
    {
257
        return config('site.name', 'HydePHP').' - '.$this->title;
258
    }
259
260
    public function renderPageMetadata(): string
261
    {
262
        return $this->metadata->render();
263
    }
264
265
    public function showInNavigation(): bool
266
    {
267
        return ! $this->navigation['hidden'];
268
    }
269
270
    public function navigationMenuPriority(): int
271
    {
272
        return $this->navigation['priority'];
273
    }
274
275
    public function navigationMenuTitle(): string
276
    {
277
        return $this->navigation['title'];
278
    }
279
}
280