Completed
Push — feature-output-formats ( 7414b6...a25fbf )
by Arnaud
08:28
created

Page::getBodyHtml()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
/*
3
 * Copyright (c) Arnaud Ligny <[email protected]>
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 */
8
9
namespace Cecil\Collection\Page;
10
11
use Cecil\Collection\Item;
12
use Cecil\Page\Parser;
13
use Cecil\Page\Type;
14
use Cecil\Page\VariableTrait;
15
use Cocur\Slugify\Slugify;
16
use Symfony\Component\Finder\SplFileInfo;
17
18
/**
19
 * Class Page.
20
 */
21
class Page extends Item
22
{
23
    use VariableTrait;
24
25
    const SLUGIFY_PATTERN = '/(^\/|[^a-z0-9\/]|-)+/';
26
    // https://regex101.com/r/tJWUrd/1
27
    const PREFIX_PATTERN = '^(.*?)(([0-9]{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])|[0-9]+)(-|_|\.)(.*)$';
28
29
    /**
30
     * @var SplFileInfo
31
     */
32
    protected $file;
33
    /**
34
     * @var string
35
     */
36
    protected $fileExtension;
37
    /**
38
     * @var string
39
     */
40
    protected $filePath;
41
    /**
42
     * @var string
43
     */
44
    protected $fileName;
45
    /**
46
     * @var string
47
     */
48
    protected $fileId;
49
    /**
50
     * @var bool
51
     */
52
    protected $virtual = false;
53
    /**
54
     * @var string
55
     */
56
    protected $type;
57
    /**
58
     * @var string
59
     */
60
    protected $id;
61
    /**
62
     * @var string
63
     */
64
    protected $pathname;
65
    /**
66
     * @var string
67
     */
68
    protected $path;
69
    /**
70
     * @var string
71
     */
72
    protected $name;
73
    /**
74
     * @var string
75
     */
76
    protected $frontmatter;
77
    /**
78
     * @var string
79
     */
80
    protected $body;
81
    /**
82
     * @var string
83
     */
84
    protected $html;
85
86
    /**
87
     * Constructor.
88
     *
89
     * @param SplFileInfo|null $file
90
     */
91
    public function __construct(SplFileInfo $file = null)
92
    {
93
        $this->file = $file;
94
95
        if ($this->file instanceof SplFileInfo) {
96
            // file extension: "md"
97
            $this->fileExtension = pathinfo($this->file, PATHINFO_EXTENSION);
98
            // file path: "Blog"
99
            $this->filePath = str_replace(DIRECTORY_SEPARATOR, '/', $this->file->getRelativePath());
100
            // file name: "Post 1"
101
            $this->fileName = basename($this->file->getBasename(), '.'.$this->fileExtension);
102
            // file id: "Blog/Post 1"
103
            $this->fileId = ($this->filePath ? $this->filePath.'/' : '')
104
                .($this->filePath && $this->fileName == 'index' ? '' : $this->fileName);
105
            /*
106
             * variables default values
107
             */
108
            // id - ie: "blog/post-1"
109
            $this->id = $this->urlize(self::subPrefix($this->fileId));
110
            // pathname - ie: "blog/post-1"
111
            $this->pathname = $this->urlize(self::subPrefix($this->fileId));
112
            // path - ie: "blog"
113
            $this->path = $this->urlize($this->filePath);
114
            // name - ie: "post-1"
115
            $this->name = $this->urlize(self::subPrefix($this->fileName));
116
            /*
117
             * front matter default values
118
             */
119
            // title - ie: "Post 1"
120
            $this->setTitle(self::subPrefix($this->fileName));
121
            // section - ie: "blog"
122
            $this->setSection(explode('/', $this->path)[0]);
123
            // date from file meta
124
            $this->setDate(filemtime($this->file->getPathname()));
125
            // file as a prefix?
126
            if (false !== self::getPrefix($this->fileId)) {
127
                // prefix is a valid date?
128
                $isValidDate = function ($date, $format = 'Y-m-d') {
129
                    $d = \DateTime::createFromFormat($format, $date);
130
131
                    return $d && $d->format($format) === $date;
132
                };
133
                if ($isValidDate(self::getPrefix($this->fileId))) {
134
                    $this->setDate((string) self::getPrefix($this->fileId));
135
                } else {
136
                    // prefix is an integer
137
                    $this->setWeight((int) self::getPrefix($this->fileId));
138
                }
139
            }
140
            // permalink
141
            $this->setPermalink($this->pathname.'/');
142
143
            parent::__construct($this->id);
144
        } else {
145
            $this->virtual = true;
146
147
            parent::__construct();
148
        }
149
        $this->setType(Type::PAGE);
150
        $this->setVariable('virtual', $this->virtual);
151
        $this->setVariable('published', true);
152
        $this->setVariable('content_template', 'page.content.twig');
153
    }
154
155
    /**
156
     * Return matches array if prefix exist or false.
157
     *
158
     * @param string $string
159
     *
160
     * @return string[]|false
161
     */
162
    public static function hasPrefix(string $string)
163
    {
164
        if (preg_match('/'.self::PREFIX_PATTERN.'/', $string, $matches)) {
165
            return $matches;
166
        } else {
167
            return false;
168
        }
169
    }
170
171
    /**
172
     * Return prefix if prefix or false.
173
     *
174
     * @param string $string
175
     *
176
     * @return string[]|false
0 ignored issues
show
Documentation introduced by
Should the return type not be string|false?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
177
     */
178
    public static function getPrefix(string $string)
179
    {
180
        if (false !== ($matches = self::hasPrefix($string))) {
181
            return $matches[2];
182
        }
183
184
        return false;
185
    }
186
187
    /**
188
     * Return string without prefix (if exist).
189
     *
190
     * @param string $string
191
     *
192
     * @return string
193
     */
194
    public static function subPrefix(string $string): string
195
    {
196
        if (false !== ($matches = self::hasPrefix($string))) {
197
            return $matches[1].$matches[7];
198
        }
199
200
        return $string;
201
    }
202
203
    /**
204
     * Format string into URL.
205
     *
206
     * @param string $string
207
     *
208
     * @return string
209
     */
210
    public static function urlize(string $string): string
211
    {
212
        return Slugify::create([
213
            'regexp' => self::SLUGIFY_PATTERN,
214
        ])->slugify($string);
215
    }
216
217
    /**
218
     * Is current page is virtual?
219
     *
220
     * @return bool
221
     */
222
    public function isVirtual(): bool
223
    {
224
        return $this->virtual;
225
    }
226
227
    /**
228
     * Set page type.
229
     *
230
     * @param string $type
231
     *
232
     * @return self
233
     */
234
    public function setType(string $type): self
235
    {
236
        $this->type = new Type($type);
0 ignored issues
show
Documentation Bug introduced by
It seems like new \Cecil\Page\Type($type) of type object<Cecil\Page\Type> is incompatible with the declared type string of property $type.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
237
238
        return $this;
239
    }
240
241
    /**
242
     * Get page type.
243
     *
244
     * @return string|null
245
     */
246
    public function getType(): ?string
247
    {
248
        return $this->type;
249
    }
250
251
    /**
252
     * Parse file content.
253
     *
254
     * @return self
255
     */
256
    public function parse(): self
257
    {
258
        $parser = new Parser($this->file);
259
        $parsed = $parser->parse();
260
        $this->frontmatter = $parsed->getFrontmatter();
261
        $this->body = $parsed->getBody();
262
263
        return $this;
264
    }
265
266
    /**
267
     * Set name.
268
     *
269
     * @param string $name
270
     *
271
     * @return self
272
     */
273
    public function setName(string $name): self
274
    {
275
        $this->name = $name;
276
277
        return $this;
278
    }
279
280
    /**
281
     * Get name.
282
     *
283
     * @return string|null
284
     */
285
    public function getName(): ?string
286
    {
287
        return $this->name;
288
    }
289
290
    /**
291
     * Set path.
292
     *
293
     * @param $path
294
     *
295
     * @return self
296
     */
297
    public function setPath(string $path): self
298
    {
299
        $this->path = $path;
300
301
        return $this;
302
    }
303
304
    /**
305
     * Get path.
306
     *
307
     * @return string
308
     */
309
    public function getPath(): string
310
    {
311
        return $this->path;
312
    }
313
314
    /**
315
     * Set path name.
316
     *
317
     * @param string $pathname
318
     *
319
     * @return self
320
     */
321
    public function setPathname(string $pathname): self
322
    {
323
        $this->pathname = $pathname;
324
325
        return $this;
326
    }
327
328
    /**
329
     * Get path name.
330
     *
331
     * @return string
332
     */
333
    public function getPathname(): string
334
    {
335
        return $this->pathname;
336
    }
337
338
    /**
339
     * Set section.
340
     *
341
     * @param string $section
342
     *
343
     * @return self
344
     */
345
    public function setSection(string $section): self
346
    {
347
        $this->setVariable('section', $section);
348
349
        return $this;
350
    }
351
352
    /**
353
     * Get section.
354
     *
355
     * @return string|false
356
     */
357
    public function getSection(): ?string
358
    {
359
        if (empty($this->getVariable('section')) && !empty($this->path)) {
360
            $this->setSection(explode('/', $this->path)[0]);
361
        }
362
363
        return $this->getVariable('section');
364
    }
365
366
    /**
367
     * Set title.
368
     *
369
     * @param string $title
370
     *
371
     * @return self
372
     */
373
    public function setTitle(string $title): self
374
    {
375
        $this->setVariable('title', $title);
376
377
        return $this;
378
    }
379
380
    /**
381
     * Get title.
382
     *
383
     * @return string|false
384
     */
385
    public function getTitle(): ?string
386
    {
387
        return $this->getVariable('title');
388
    }
389
390
    /**
391
     * Set date.
392
     *
393
     * @param string|\DateTime $date
394
     *
395
     * @return self
396
     */
397
    public function setDate($date): self
398
    {
399
        $this->setVariable('date', $date);
400
401
        return $this;
402
    }
403
404
    /**
405
     * Get Date.
406
     *
407
     * @return \DateTime|false
408
     */
409
    public function getDate(): ?\DateTime
410
    {
411
        return $this->getVariable('date');
412
    }
413
414
    /**
415
     * Set weight.
416
     *
417
     * @param int $weight
418
     *
419
     * @return self
420
     */
421
    public function setWeight(int $weight): self
422
    {
423
        $this->setVariable('weight', $weight);
424
425
        return $this;
426
    }
427
428
    /**
429
     * Get weight.
430
     *
431
     * @return int|null
432
     */
433
    public function getWeight(): ?int
434
    {
435
        return $this->getVariable('weight');
436
    }
437
438
    /**
439
     * Set permalink.
440
     *
441
     * @param string $permalink
442
     *
443
     * @return self
444
     */
445
    public function setPermalink(string $permalink): self
446
    {
447
        $this->setVariable('permalink', $permalink);
448
449
        return $this;
450
    }
451
452
    /**
453
     * Get permalink.
454
     *
455
     * @return string|false
456
     */
457
    public function getPermalink(): ?string
458
    {
459
        if (empty($this->getVariable('permalink'))) {
460
            $this->setPermalink($this->getPathname().'/');
461
        }
462
463
        return $this->getVariable('permalink');
464
    }
465
466
    /**
467
     * Get frontmatter.
468
     *
469
     * @return string|null
470
     */
471
    public function getFrontmatter(): ?string
472
    {
473
        return $this->frontmatter;
474
    }
475
476
    /**
477
     * Get body as raw.
478
     *
479
     * @return string
480
     */
481
    public function getBody(): ?string
482
    {
483
        return $this->body;
484
    }
485
486
    /**
487
     * Set body as HTML.
488
     *
489
     * @param string $html
490
     *
491
     * @return self
492
     */
493
    public function setBodyHtml(string $html): self
494
    {
495
        $this->html = $html;
496
497
        return $this;
498
    }
499
500
    /**
501
     * Get body as HTML.
502
     *
503
     * @return string|null
504
     */
505
    public function getBodyHtml(): ?string
506
    {
507
        return $this->html;
508
    }
509
510
    /**
511
     * @see getBodyHtml()
512
     *
513
     * @return string|null
514
     */
515
    public function getContent(): ?string
516
    {
517
        return $this->getBodyHtml();
518
    }
519
520
    /**
521
     * Set layout.
522
     *
523
     * @param string $layout
524
     *
525
     * @return self
526
     */
527
    public function setLayout(string $layout): self
528
    {
529
        $this->setVariable('layout', $layout);
530
531
        return $this;
532
    }
533
534
    /**
535
     * Get layout.
536
     *
537
     * @return string|false
538
     */
539
    public function getLayout(): ?string
540
    {
541
        return $this->getVariable('layout');
542
    }
543
}
544