1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* @copyright 2017 Vladimir Jimenez |
5
|
|
|
* @license https://github.com/allejo/stakx/blob/master/LICENSE.md MIT |
6
|
|
|
*/ |
7
|
|
|
|
8
|
|
|
namespace allejo\stakx\FrontMatter; |
9
|
|
|
|
10
|
|
|
use allejo\stakx\Document\JailedDocumentInterface; |
11
|
|
|
use allejo\stakx\Exception\FileAwareException; |
12
|
|
|
use allejo\stakx\Exception\InvalidSyntaxException; |
13
|
|
|
use allejo\stakx\FrontMatter\Exception\YamlVariableUndefinedException; |
14
|
|
|
use allejo\stakx\System\Filesystem; |
15
|
|
|
use Symfony\Component\Filesystem\Exception\FileNotFoundException; |
16
|
|
|
use Symfony\Component\Filesystem\Exception\IOException; |
17
|
|
|
use Symfony\Component\Finder\SplFileInfo; |
18
|
|
|
use Symfony\Component\Yaml\Exception\ParseException; |
19
|
|
|
use Symfony\Component\Yaml\Yaml; |
20
|
|
|
|
21
|
|
|
abstract class Document implements WritableDocumentInterface, JailedDocumentInterface, \ArrayAccess |
|
|
|
|
22
|
|
|
{ |
23
|
|
|
const TEMPLATE = "---\n%s\n---\n\n%s"; |
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* The names of FrontMatter keys that are specially defined for all Documents |
27
|
|
|
* |
28
|
|
|
* @var array |
29
|
|
|
*/ |
30
|
|
|
public static $specialFrontMatterKeys = array( |
|
|
|
|
31
|
|
|
'filename', 'basename' |
32
|
|
|
); |
33
|
|
|
|
34
|
|
|
protected static $whiteListFunctions = array( |
35
|
|
|
'getPermalink', 'getRedirects', 'getTargetFile', 'getName', 'getFilePath', 'getRelativeFilePath', 'getContent', |
36
|
|
|
'getExtension', 'getFrontMatter' |
37
|
|
|
); |
38
|
|
|
|
39
|
|
|
/** |
40
|
|
|
* An array to keep track of collection or data dependencies used inside of a Twig template. |
41
|
|
|
* |
42
|
|
|
* $dataDependencies['collections'] = array() |
43
|
|
|
* $dataDependencies['data'] = array() |
44
|
|
|
* |
45
|
|
|
* @var array |
46
|
|
|
*/ |
47
|
|
|
protected $dataDependencies; |
48
|
|
|
|
49
|
|
|
/** |
50
|
|
|
* FrontMatter values that can be injected or set after the file has been parsed. Values in this array will take |
51
|
|
|
* precedence over values in $frontMatter. |
52
|
|
|
* |
53
|
|
|
* @var array |
54
|
|
|
*/ |
55
|
|
|
protected $writableFrontMatter; |
56
|
|
|
|
57
|
|
|
/** |
58
|
|
|
* A list of Front Matter values that should not be returned directly from the $frontMatter array. Values listed |
59
|
|
|
* here have dedicated functions that handle those Front Matter values and the respective functions should be called |
60
|
|
|
* instead. |
61
|
|
|
* |
62
|
|
|
* @var string[] |
63
|
|
|
*/ |
64
|
|
|
protected $frontMatterBlacklist; |
65
|
|
|
|
66
|
|
|
/** |
67
|
|
|
* Set to true if the front matter has already been evaluated with variable interpolation. |
68
|
|
|
* |
69
|
|
|
* @var bool |
70
|
|
|
*/ |
71
|
|
|
protected $frontMatterEvaluated; |
72
|
|
|
|
73
|
|
|
/** |
74
|
|
|
* @var Parser |
75
|
|
|
*/ |
76
|
|
|
protected $frontMatterParser; |
77
|
|
|
|
78
|
|
|
/** |
79
|
|
|
* An array containing the Yaml of the file. |
80
|
|
|
* |
81
|
|
|
* @var array |
82
|
|
|
*/ |
83
|
|
|
protected $frontMatter; |
84
|
|
|
|
85
|
|
|
/** |
86
|
|
|
* Set to true if the body has already been parsed as markdown or any other format. |
87
|
|
|
* |
88
|
|
|
* @var bool |
89
|
|
|
*/ |
90
|
|
|
protected $bodyContentEvaluated; |
91
|
|
|
|
92
|
|
|
/** |
93
|
|
|
* Only the body of the file, i.e. the content. |
94
|
|
|
* |
95
|
|
|
* @var string |
96
|
|
|
*/ |
97
|
|
|
protected $bodyContent; |
98
|
|
|
|
99
|
|
|
/** |
100
|
|
|
* The permalink for this object. |
101
|
|
|
* |
102
|
|
|
* @var string |
103
|
|
|
*/ |
104
|
|
|
protected $permalink; |
105
|
|
|
|
106
|
|
|
/** |
107
|
|
|
* A filesystem object. |
108
|
|
|
* |
109
|
|
|
* @var Filesystem |
110
|
|
|
*/ |
111
|
|
|
protected $fs; |
|
|
|
|
112
|
|
|
|
113
|
|
|
/** |
114
|
|
|
* The extension of the file. |
115
|
|
|
* |
116
|
|
|
* @var string |
117
|
|
|
*/ |
118
|
|
|
private $extension; |
119
|
|
|
|
120
|
|
|
/** |
121
|
|
|
* The number of lines that Twig template errors should offset. |
122
|
|
|
* |
123
|
|
|
* @var int |
124
|
|
|
*/ |
125
|
|
|
private $lineOffset; |
126
|
|
|
|
127
|
|
|
/** |
128
|
|
|
* A list URLs that will redirect to this object. |
129
|
|
|
* |
130
|
|
|
* @var string[] |
131
|
|
|
*/ |
132
|
|
|
private $redirects; |
133
|
|
|
|
134
|
|
|
/** |
135
|
|
|
* The original file path to the ContentItem. |
136
|
|
|
* |
137
|
|
|
* @var SplFileInfo |
138
|
|
|
*/ |
139
|
|
|
private $filePath; |
140
|
|
|
|
141
|
|
|
/** |
142
|
|
|
* ContentItem constructor. |
143
|
|
|
* |
144
|
|
|
* @param string $filePath The path to the file that will be parsed into a ContentItem |
145
|
|
|
* |
146
|
|
|
* @throws FileNotFoundException The given file path does not exist |
147
|
|
|
* @throws IOException The file was not a valid ContentItem. This would meam there was no front matter or |
148
|
|
|
* no body |
149
|
|
|
*/ |
150
|
116 |
|
public function __construct($filePath) |
151
|
|
|
{ |
152
|
116 |
|
$this->frontMatterBlacklist = array('permalink', 'redirects'); |
153
|
116 |
|
$this->writableFrontMatter = array(); |
154
|
|
|
|
155
|
116 |
|
$this->filePath = $filePath; |
|
|
|
|
156
|
116 |
|
$this->fs = new Filesystem(); |
157
|
|
|
|
158
|
116 |
|
if (!$this->fs->exists($filePath)) |
159
|
116 |
|
{ |
160
|
1 |
|
throw new FileNotFoundException("The following file could not be found: ${filePath}"); |
161
|
|
|
} |
162
|
|
|
|
163
|
|
|
$this->extension = strtolower($this->fs->getExtension($filePath)); |
164
|
|
|
|
165
|
|
|
$this->refreshFileContent(); |
166
|
|
|
} |
167
|
|
|
|
168
|
|
|
/** |
169
|
|
|
* Return the body of the Content Item. |
170
|
|
|
* |
171
|
|
|
* @return string |
172
|
|
|
*/ |
173
|
|
|
abstract public function getContent(); |
174
|
|
|
|
175
|
|
|
/** |
176
|
|
|
* Get the extension of the current file. |
177
|
|
|
* |
178
|
|
|
* @return string |
179
|
|
|
*/ |
180
|
|
|
final public function getExtension() |
181
|
|
|
{ |
182
|
7 |
|
return $this->extension; |
183
|
|
|
} |
184
|
|
|
|
185
|
|
|
/** |
186
|
|
|
* Get the original file path. |
187
|
|
|
* |
188
|
|
|
* @return string |
|
|
|
|
189
|
|
|
*/ |
190
|
|
|
final public function getFilePath() |
191
|
|
|
{ |
192
|
19 |
|
return $this->filePath; |
193
|
|
|
} |
194
|
|
|
|
195
|
|
|
/** |
196
|
|
|
* The number of lines that are taken up by FrontMatter and white space. |
197
|
|
|
* |
198
|
|
|
* @return int |
199
|
|
|
*/ |
200
|
|
|
final public function getLineOffset() |
201
|
|
|
{ |
202
|
|
|
return $this->lineOffset; |
203
|
|
|
} |
204
|
|
|
|
205
|
|
|
/** |
206
|
|
|
* Get the name of the item, which is just the filename without the extension. |
207
|
|
|
* |
208
|
|
|
* @return string |
209
|
|
|
*/ |
210
|
|
|
final public function getName() |
211
|
|
|
{ |
212
|
62 |
|
return $this->fs->getBaseName($this->filePath); |
213
|
|
|
} |
214
|
|
|
|
215
|
|
|
/** |
216
|
|
|
* Get the filename of this document. |
217
|
|
|
* |
218
|
|
|
* @return string |
219
|
|
|
*/ |
220
|
|
|
final public function getFileName() |
221
|
|
|
{ |
222
|
30 |
|
return $this->fs->getFileName($this->filePath); |
223
|
|
|
} |
224
|
|
|
|
225
|
|
|
/** |
226
|
|
|
* Get the relative path to this file relative to the root of the Stakx website. |
227
|
|
|
* |
228
|
|
|
* @return string |
229
|
|
|
*/ |
230
|
|
|
final public function getRelativeFilePath() |
231
|
|
|
{ |
232
|
65 |
|
if ($this->filePath instanceof SplFileInfo) |
233
|
65 |
|
{ |
234
|
39 |
|
return $this->filePath->getRelativePathname(); |
235
|
|
|
} |
236
|
|
|
|
237
|
|
|
// TODO ensure that we always get SplFileInfo objects, even when handling VFS documents |
238
|
28 |
|
return $this->fs->getRelativePath($this->filePath); |
239
|
|
|
} |
240
|
|
|
|
241
|
|
|
/** |
242
|
|
|
* Get the destination of where this Content Item would be written to when the website is compiled. |
243
|
|
|
* |
244
|
|
|
* @return string |
245
|
|
|
*/ |
246
|
|
|
final public function getTargetFile() |
247
|
|
|
{ |
248
|
20 |
|
$permalink = $this->getPermalink(); |
249
|
20 |
|
$missingFile = (substr($permalink, -1) == '/'); |
250
|
20 |
|
$permalink = str_replace('/', DIRECTORY_SEPARATOR, $permalink); |
251
|
|
|
|
252
|
|
|
if ($missingFile) |
253
|
20 |
|
{ |
254
|
12 |
|
$permalink = rtrim($permalink, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'index.html'; |
255
|
12 |
|
} |
256
|
|
|
|
257
|
20 |
|
return ltrim($permalink, DIRECTORY_SEPARATOR); |
258
|
|
|
} |
259
|
|
|
|
260
|
|
|
/** |
261
|
|
|
* Check whether this object has a reference to a collection or data item. |
262
|
|
|
* |
263
|
|
|
* @param string $namespace 'collections' or 'data' |
264
|
|
|
* @param string $needle |
265
|
|
|
* |
266
|
|
|
* @return bool |
267
|
|
|
*/ |
268
|
|
|
final public function hasTwigDependency($namespace, $needle) |
269
|
|
|
{ |
270
|
|
|
return in_array($needle, $this->dataDependencies[$namespace]); |
271
|
|
|
} |
272
|
|
|
|
273
|
|
|
/** |
274
|
|
|
* Read the file, and parse its contents. |
275
|
|
|
*/ |
276
|
|
|
final public function refreshFileContent() |
277
|
|
|
{ |
278
|
|
|
// This function can be called after the initial object was created and the file may have been deleted since the |
279
|
|
|
// creation of the object. |
280
|
115 |
|
if (!$this->fs->exists($this->filePath)) |
281
|
115 |
|
{ |
282
|
1 |
|
throw new FileNotFoundException(null, 0, null, $this->filePath); |
283
|
|
|
} |
284
|
|
|
|
285
|
|
|
// $fileStructure[1] is the YAML |
|
|
|
|
286
|
|
|
// $fileStructure[2] is the amount of new lines after the closing `---` and the beginning of content |
287
|
|
|
// $fileStructure[3] is the body of the document |
288
|
115 |
|
$fileStructure = array(); |
289
|
|
|
|
290
|
115 |
|
$rawFileContents = file_get_contents($this->filePath); |
291
|
115 |
|
preg_match('/---\R(.*?\R)?---(\s+)(.*)/s', $rawFileContents, $fileStructure); |
292
|
|
|
|
293
|
115 |
|
if (count($fileStructure) != 4) |
294
|
115 |
|
{ |
295
|
9 |
|
throw new InvalidSyntaxException('Invalid FrontMatter file', 0, null, $this->getRelativeFilePath()); |
296
|
|
|
} |
297
|
|
|
|
298
|
106 |
|
if (empty(trim($fileStructure[3]))) |
299
|
106 |
|
{ |
300
|
1 |
|
throw new InvalidSyntaxException('FrontMatter files must have a body to render', 0, null, $this->getRelativeFilePath()); |
301
|
|
|
} |
302
|
|
|
|
303
|
|
|
// The hard coded 1 is the offset used to count the new line used after the first `---` that is not caught in the regex |
304
|
105 |
|
$this->lineOffset = substr_count($fileStructure[1], "\n") + substr_count($fileStructure[2], "\n") + 1; |
305
|
105 |
|
$this->bodyContent = $fileStructure[3]; |
306
|
|
|
|
307
|
105 |
|
if (!empty(trim($fileStructure[1]))) |
308
|
105 |
|
{ |
309
|
89 |
|
$this->frontMatter = Yaml::parse($fileStructure[1], Yaml::PARSE_DATETIME); |
|
|
|
|
310
|
|
|
|
311
|
89 |
|
if (!empty($this->frontMatter) && !is_array($this->frontMatter)) |
312
|
89 |
|
{ |
313
|
1 |
|
throw new ParseException('The evaluated FrontMatter should be an array'); |
314
|
|
|
} |
315
|
88 |
|
} |
316
|
|
|
else |
317
|
|
|
{ |
318
|
19 |
|
$this->frontMatter = array(); |
319
|
|
|
} |
320
|
|
|
|
321
|
104 |
|
$this->frontMatterEvaluated = false; |
322
|
104 |
|
$this->bodyContentEvaluated = false; |
323
|
104 |
|
$this->permalink = null; |
324
|
|
|
|
325
|
104 |
|
$this->findTwigDataDependencies('collections'); |
326
|
104 |
|
$this->findTwigDataDependencies('data'); |
327
|
104 |
|
} |
328
|
|
|
|
329
|
|
|
/** |
330
|
|
|
* Get all of the references to either DataItems or ContentItems inside of given string. |
331
|
|
|
* |
332
|
|
|
* @param string $filter 'collections' or 'data' |
333
|
|
|
*/ |
334
|
|
|
private function findTwigDataDependencies($filter) |
335
|
|
|
{ |
336
|
104 |
|
$regex = '/{[{%](?:.+)?(?:' . $filter . ')(?:\.|\[\')(\w+)(?:\'\])?.+[%}]}/'; |
337
|
104 |
|
$results = array(); |
338
|
|
|
|
339
|
104 |
|
preg_match_all($regex, $this->bodyContent, $results); |
340
|
|
|
|
341
|
104 |
|
$this->dataDependencies[$filter] = array_unique($results[1]); |
342
|
104 |
|
} |
343
|
|
|
|
344
|
|
|
// |
345
|
|
|
// Permalink and redirect functionality |
346
|
|
|
// |
347
|
|
|
|
348
|
|
|
/** |
349
|
|
|
* Get the permalink of this Content Item. |
350
|
|
|
* |
351
|
|
|
* @throws \Exception |
352
|
|
|
* |
353
|
|
|
* @return string |
354
|
|
|
*/ |
355
|
|
|
final public function getPermalink() |
356
|
|
|
{ |
357
|
39 |
|
if (!is_null($this->permalink)) |
358
|
39 |
|
{ |
359
|
8 |
|
return $this->permalink; |
360
|
|
|
} |
361
|
|
|
|
362
|
37 |
|
if (!is_null($this->frontMatterParser) && $this->frontMatterParser->hasExpansion()) |
363
|
37 |
|
{ |
364
|
|
|
throw new \Exception('The permalink for this item has not been set'); |
365
|
|
|
} |
366
|
|
|
|
367
|
37 |
|
$permalink = (is_array($this->frontMatter) && isset($this->frontMatter['permalink'])) ? |
368
|
37 |
|
$this->frontMatter['permalink'] : $this->getPathPermalink(); |
369
|
|
|
|
370
|
37 |
|
if (is_array($permalink)) |
371
|
37 |
|
{ |
372
|
19 |
|
$this->permalink = $permalink[0]; |
373
|
19 |
|
array_shift($permalink); |
374
|
19 |
|
$this->redirects = $permalink; |
375
|
19 |
|
} |
376
|
|
|
else |
377
|
|
|
{ |
378
|
24 |
|
$this->permalink = $permalink; |
379
|
24 |
|
$this->redirects = array(); |
380
|
|
|
} |
381
|
|
|
|
382
|
37 |
|
$this->permalink = $this->sanitizePermalink($this->permalink); |
383
|
37 |
|
$this->permalink = str_replace(DIRECTORY_SEPARATOR, '/', $this->permalink); |
384
|
37 |
|
$this->permalink = '/' . ltrim($this->permalink, '/'); // Permalinks should always use '/' and not be OS specific |
385
|
|
|
|
386
|
37 |
|
return $this->permalink; |
387
|
|
|
} |
388
|
|
|
|
389
|
|
|
/** |
390
|
|
|
* Get an array of URLs that will redirect to. |
391
|
|
|
* |
392
|
|
|
* @return string[] |
|
|
|
|
393
|
|
|
*/ |
394
|
|
|
final public function getRedirects() |
395
|
|
|
{ |
396
|
14 |
|
if (is_null($this->redirects)) |
397
|
14 |
|
{ |
398
|
3 |
|
$this->getPermalink(); |
399
|
3 |
|
} |
400
|
|
|
|
401
|
14 |
|
return $this->redirects; |
402
|
|
|
} |
403
|
|
|
|
404
|
|
|
/** |
405
|
|
|
* Get the permalink based off the location of where the file is relative to the website. This permalink is to be |
406
|
|
|
* used as a fallback in the case that a permalink is not explicitly specified in the Front Matter. |
407
|
|
|
* |
408
|
|
|
* @return string |
409
|
|
|
*/ |
410
|
|
|
private function getPathPermalink() |
411
|
|
|
{ |
412
|
|
|
// Remove the protocol of the path, if there is one and prepend a '/' to the beginning |
413
|
3 |
|
$cleanPath = preg_replace('/[\w|\d]+:\/\//', '', $this->getRelativeFilePath()); |
414
|
3 |
|
$cleanPath = ltrim($cleanPath, DIRECTORY_SEPARATOR); |
415
|
|
|
|
416
|
|
|
// Handle vfs:// paths by replacing their forward slashes with the OS appropriate directory separator |
417
|
3 |
|
if (DIRECTORY_SEPARATOR !== '/') |
418
|
3 |
|
{ |
419
|
|
|
$cleanPath = str_replace('/', DIRECTORY_SEPARATOR, $cleanPath); |
420
|
|
|
} |
421
|
|
|
|
422
|
|
|
// Check the first folder and see if it's a data folder (starts with an underscore) intended for stakx |
423
|
3 |
|
$folders = explode(DIRECTORY_SEPARATOR, $cleanPath); |
424
|
|
|
|
425
|
3 |
|
if (substr($folders[0], 0, 1) === '_') |
426
|
3 |
|
{ |
427
|
1 |
|
array_shift($folders); |
428
|
1 |
|
} |
429
|
|
|
|
430
|
3 |
|
$cleanPath = implode(DIRECTORY_SEPARATOR, $folders); |
431
|
|
|
|
432
|
3 |
|
return $cleanPath; |
433
|
|
|
} |
434
|
|
|
|
435
|
|
|
/** |
436
|
|
|
* Sanitize a permalink to remove unsupported characters or multiple '/' and replace spaces with hyphens. |
437
|
|
|
* |
438
|
|
|
* @param string $permalink A permalink |
439
|
|
|
* |
440
|
|
|
* @return string $permalink The sanitized permalink |
441
|
|
|
*/ |
442
|
|
|
private function sanitizePermalink($permalink) |
443
|
|
|
{ |
444
|
|
|
// Remove multiple '/' together |
445
|
37 |
|
$permalink = preg_replace('/\/+/', '/', $permalink); |
|
|
|
|
446
|
|
|
|
447
|
|
|
// Replace all spaces with hyphens |
448
|
37 |
|
$permalink = str_replace(' ', '-', $permalink); |
|
|
|
|
449
|
|
|
|
450
|
|
|
// Remove all disallowed characters |
451
|
37 |
|
$permalink = preg_replace('/[^0-9a-zA-Z-_\/\\\.]/', '', $permalink); |
|
|
|
|
452
|
|
|
|
453
|
|
|
// Handle unnecessary extensions |
454
|
37 |
|
$extensionsToStrip = array('twig'); |
455
|
|
|
|
456
|
37 |
|
if (in_array($this->fs->getExtension($permalink), $extensionsToStrip)) |
457
|
37 |
|
{ |
458
|
4 |
|
$permalink = $this->fs->removeExtension($permalink); |
|
|
|
|
459
|
4 |
|
} |
460
|
|
|
|
461
|
|
|
// Remove any special characters before a sane value |
462
|
37 |
|
$permalink = preg_replace('/^[^0-9a-zA-Z-_]*/', '', $permalink); |
|
|
|
|
463
|
|
|
|
464
|
|
|
// Convert permalinks to lower case |
465
|
37 |
|
$permalink = mb_strtolower($permalink, 'UTF-8'); |
|
|
|
|
466
|
|
|
|
467
|
37 |
|
return $permalink; |
468
|
|
|
} |
469
|
|
|
|
470
|
|
|
// |
471
|
|
|
// WritableFrontMatter Implementation |
472
|
|
|
// |
473
|
|
|
|
474
|
|
|
/** |
475
|
|
|
* {@inheritdoc} |
476
|
|
|
*/ |
477
|
|
|
final public function evaluateFrontMatter($variables = null) |
478
|
|
|
{ |
479
|
7 |
|
if (!is_null($variables)) |
480
|
7 |
|
{ |
481
|
7 |
|
$this->frontMatter = array_merge($this->frontMatter, $variables); |
482
|
7 |
|
$this->evaluateYaml($this->frontMatter); |
483
|
7 |
|
} |
484
|
7 |
|
} |
485
|
|
|
|
486
|
|
|
/** |
487
|
|
|
* {@inheritdoc} |
488
|
|
|
*/ |
489
|
|
|
final public function getFrontMatter($evaluateYaml = true) |
490
|
|
|
{ |
491
|
29 |
|
if (is_null($this->frontMatter)) |
492
|
29 |
|
{ |
493
|
|
|
$this->frontMatter = array(); |
494
|
|
|
} |
495
|
29 |
|
elseif (!$this->frontMatterEvaluated && $evaluateYaml) |
496
|
|
|
{ |
497
|
23 |
|
$this->evaluateYaml($this->frontMatter); |
498
|
22 |
|
} |
499
|
|
|
|
500
|
28 |
|
return $this->frontMatter; |
501
|
|
|
} |
502
|
|
|
|
503
|
|
|
/** |
504
|
|
|
* {@inheritdoc} |
505
|
|
|
*/ |
506
|
|
|
final public function hasExpandedFrontMatter() |
507
|
|
|
{ |
508
|
2 |
|
return !is_null($this->frontMatterParser) && $this->frontMatterParser->hasExpansion(); |
509
|
|
|
} |
510
|
|
|
|
511
|
|
|
/** |
512
|
|
|
* {@inheritdoc. |
513
|
|
|
*/ |
514
|
|
|
final public function appendFrontMatter(array $frontMatter) |
515
|
|
|
{ |
516
|
|
|
foreach ($frontMatter as $key => $value) |
517
|
|
|
{ |
518
|
|
|
$this->writableFrontMatter[$key] = $value; |
519
|
|
|
} |
520
|
|
|
} |
521
|
|
|
|
522
|
|
|
/** |
523
|
|
|
* {@inheritdoc. |
524
|
|
|
*/ |
525
|
|
|
final public function deleteFrontMatter($key) |
526
|
|
|
{ |
527
|
|
|
if (!isset($this->writableFrontMatter[$key])) |
528
|
|
|
{ |
529
|
|
|
return; |
530
|
|
|
} |
531
|
|
|
|
532
|
|
|
unset($this->writableFrontMatter[$key]); |
533
|
|
|
} |
534
|
|
|
|
535
|
|
|
/** |
536
|
|
|
* {@inheritdoc. |
537
|
|
|
*/ |
538
|
|
|
final public function setFrontMatter(array $frontMatter) |
539
|
|
|
{ |
540
|
2 |
|
if (!is_array($frontMatter)) |
541
|
2 |
|
{ |
542
|
|
|
throw new \InvalidArgumentException('An array is required for setting the writable FrontMatter'); |
543
|
|
|
} |
544
|
|
|
|
545
|
2 |
|
$this->writableFrontMatter = $frontMatter; |
546
|
2 |
|
} |
547
|
|
|
|
548
|
|
|
/** |
549
|
|
|
* Evaluate an array of data for FrontMatter variables. This function will modify the array in place. |
550
|
|
|
* |
551
|
|
|
* @param array $yaml An array of data containing FrontMatter variables |
552
|
|
|
* |
553
|
|
|
* @throws YamlVariableUndefinedException A FrontMatter variable used does not exist |
554
|
|
|
*/ |
555
|
|
|
private function evaluateYaml(&$yaml) |
556
|
|
|
{ |
557
|
|
|
try |
558
|
|
|
{ |
559
|
30 |
|
$this->frontMatterParser = new Parser($yaml, array( |
560
|
30 |
|
'filename' => $this->getFileName(), |
561
|
30 |
|
'basename' => $this->getName(), |
562
|
30 |
|
)); |
563
|
29 |
|
$this->frontMatterEvaluated = true; |
564
|
|
|
} |
565
|
30 |
|
catch (\Exception $e) |
566
|
|
|
{ |
567
|
1 |
|
throw FileAwareException::castException($e, $this->getRelativeFilePath()); |
568
|
|
|
} |
569
|
29 |
|
} |
570
|
|
|
|
571
|
|
|
// |
572
|
|
|
// ArrayAccess Implementation |
573
|
|
|
// |
574
|
|
|
|
575
|
|
|
/** |
576
|
|
|
* {@inheritdoc} |
577
|
|
|
*/ |
578
|
|
|
public function offsetSet($offset, $value) |
579
|
|
|
{ |
580
|
|
|
if (is_null($offset)) |
581
|
|
|
{ |
582
|
|
|
throw new \InvalidArgumentException('$offset cannot be null'); |
583
|
|
|
} |
584
|
|
|
|
585
|
|
|
$this->writableFrontMatter[$offset] = $value; |
586
|
|
|
} |
587
|
|
|
|
588
|
|
|
/** |
589
|
|
|
* {@inheritdoc} |
590
|
|
|
*/ |
591
|
|
|
public function offsetExists($offset) |
592
|
|
|
{ |
593
|
31 |
|
if (isset($this->writableFrontMatter[$offset]) || isset($this->frontMatter[$offset])) |
594
|
31 |
|
{ |
595
|
30 |
|
return true; |
596
|
|
|
} |
597
|
|
|
|
598
|
14 |
|
$fxnCall = 'get' . ucfirst($offset); |
599
|
|
|
|
600
|
14 |
|
return method_exists($this, $fxnCall) && in_array($fxnCall, static::$whiteListFunctions); |
601
|
|
|
} |
602
|
|
|
|
603
|
|
|
/** |
604
|
|
|
* {@inheritdoc} |
605
|
|
|
*/ |
606
|
|
|
public function offsetUnset($offset) |
607
|
|
|
{ |
608
|
|
|
unset($this->writableFrontMatter[$offset]); |
609
|
|
|
} |
610
|
|
|
|
611
|
|
|
/** |
612
|
|
|
* {@inheritdoc} |
613
|
|
|
*/ |
614
|
|
|
public function offsetGet($offset) |
615
|
|
|
{ |
616
|
48 |
|
$fxnCall = 'get' . ucfirst($offset); |
617
|
|
|
|
618
|
48 |
|
if (in_array($fxnCall, self::$whiteListFunctions) && method_exists($this, $fxnCall)) |
619
|
48 |
|
{ |
620
|
6 |
|
return call_user_func_array(array($this, $fxnCall), array()); |
621
|
|
|
} |
622
|
|
|
|
623
|
42 |
|
if (isset($this->writableFrontMatter[$offset])) |
624
|
42 |
|
{ |
625
|
|
|
return $this->writableFrontMatter[$offset]; |
626
|
|
|
} |
627
|
|
|
|
628
|
42 |
|
if (isset($this->frontMatter[$offset])) |
629
|
42 |
|
{ |
630
|
41 |
|
return $this->frontMatter[$offset]; |
631
|
|
|
} |
632
|
|
|
|
633
|
5 |
|
return null; |
634
|
|
|
} |
635
|
|
|
} |
636
|
|
|
|
This check examines a number of code elements and verifies that they conform to the given naming conventions.
You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.