Passed
Push — paginator ( 186766 )
by Arnaud
04:05
created

Page::setVariable()   C

Complexity

Conditions 15
Paths 16

Size

Total Lines 65
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 25
CRAP Score 16.0422

Importance

Changes 4
Bugs 2 Features 0
Metric Value
cc 15
eloc 33
c 4
b 2
f 0
nc 16
nop 2
dl 0
loc 65
ccs 25
cts 30
cp 0.8333
crap 16.0422
rs 5.9166

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of Cecil.
7
 *
8
 * Copyright (c) Arnaud Ligny <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Cecil\Collection\Page;
15
16
use Cecil\Collection\Item;
17
use Cecil\Exception\RuntimeException;
18
use Cecil\Util;
19
use Cocur\Slugify\Slugify;
20
use Symfony\Component\Finder\SplFileInfo;
21
22
/**
23
 * Class Page.
24
 */
25
class Page extends Item
26
{
27
    const SLUGIFY_PATTERN = '/(^\/|[^._a-z0-9\/]|-)+/'; // should be '/^\/|[^_a-z0-9\/]+/'
28
29
    /** @var bool True if page is not created from a Markdown file. */
30
    protected $virtual;
31
32
    /** @var SplFileInfo */
33
    protected $file;
34
35
    /** @var string Homepage, Page, Section, etc. */
36
    protected $type;
37
38
    /** @var string */
39
    protected $folder;
40
41
    /** @var string */
42
    protected $slug;
43
44
    /** @var string folder + slug. */
45
    protected $path;
46
47
    /** @var string */
48
    protected $section;
49
50
    /** @var string */
51
    protected $frontmatter;
52
53
    /** @var array Front matter before conversion. */
54
    protected $fmVariables = [];
55
56
    /** @var string Body before conversion. */
57
    protected $body;
58
59
    /** @var string Body after Markdown conversion. */
60
    protected $html;
61
62
    /** @var array Output by format */
63
    protected $rendered = [];
64
65
    /** @var \Cecil\Collection\Page\Collection Subpages of a section */
66
    protected $subPages;
67
68
    /** @var array */
69
    protected $paginator = [];
70
71
    /** @var \Cecil\Collection\Taxonomy\Vocabulary Terms of a vocabulary */
72
    protected $terms;
73
74
    /** @var Slugify */
75
    private static $slugifier;
76
77 1
    public function __construct(string $id)
78
    {
79 1
        parent::__construct($id);
80 1
        $this->setVirtual(true);
81 1
        $this->setType(Type::PAGE);
82
        // default variables
83 1
        $this->setVariables([
84
            'title'            => 'Page Title',
85 1
            'date'             => new \DateTime(),
86 1
            'updated'          => new \DateTime(),
87
            'weight'           => null,
88
            'filepath'         => null,
89
            'published'        => true,
90
            'content_template' => 'page.content.twig',
91
        ]);
92
    }
93
94
    /**
95
     * Turns a path (string) into a slug (URI).
96
     */
97 1
    public static function slugify(string $path): string
98
    {
99 1
        if (!self::$slugifier instanceof Slugify) {
100 1
            self::$slugifier = Slugify::create(['regexp' => self::SLUGIFY_PATTERN]);
101
        }
102
103 1
        return self::$slugifier->slugify($path);
104
    }
105
106
    /**
107
     * Creates the ID from the file path.
108
     */
109 1
    public static function createId(SplFileInfo $file): string
110
    {
111 1
        $relativepath = self::slugify(str_replace(DIRECTORY_SEPARATOR, '/', $file->getRelativePath()));
112 1
        $basename = self::slugify(PrefixSuffix::subPrefix($file->getBasename('.'.$file->getExtension())));
113
        // case of "README" -> index
114 1
        $basename = (string) str_ireplace('readme', 'index', $basename);
115
        // case of section's index: "section/index" -> "section"
116 1
        if (!empty($relativepath) && PrefixSuffix::sub($basename) == 'index') {
117
            // case of a localized section
118 1
            if (PrefixSuffix::hasSuffix($basename)) {
119 1
                return $relativepath.'.'.PrefixSuffix::getSuffix($basename);
120
            }
121
122 1
            return $relativepath;
123
        }
124
125 1
        return trim(Util::joinPath($relativepath, $basename), '/');
126
    }
127
128
    /**
129
     * Returns the ID of a page without language suffix.
130
     */
131 1
    public function getIdWithoutLang(): string
132
    {
133 1
        return PrefixSuffix::sub($this->getId());
134
    }
135
136
    /**
137
     * Set file.
138
     */
139 1
    public function setFile(SplFileInfo $file): self
140
    {
141 1
        $this->setVirtual(false);
142 1
        $this->file = $file;
143
144
        /*
145
         * File path components
146
         */
147 1
        $fileRelativePath = str_replace(DIRECTORY_SEPARATOR, '/', $this->file->getRelativePath());
148 1
        $fileExtension = $this->file->getExtension();
149 1
        $fileName = $this->file->getBasename('.'.$fileExtension);
150
        // case of "README" -> "index"
151 1
        $fileName = (string) str_ireplace('readme', 'index', $fileName);
152
        // case of "index" = home page
153 1
        if (empty($this->file->getRelativePath()) && PrefixSuffix::sub($fileName) == 'index') {
154 1
            $this->setType(Type::HOMEPAGE);
155
        }
156
        /*
157
         * Set protected variables
158
         */
159 1
        $this->setFolder($fileRelativePath); // ie: "blog"
160 1
        $this->setSlug($fileName); // ie: "post-1"
161 1
        $this->setPath($this->getFolder().'/'.$this->getSlug()); // ie: "blog/post-1"
162
        /*
163
         * Set default variables
164
         */
165 1
        $this->setVariables([
166 1
            'title'    => PrefixSuffix::sub($fileName),
167 1
            'date'     => (new \DateTime())->setTimestamp($this->file->getMTime()),
168 1
            'updated'  => (new \DateTime())->setTimestamp($this->file->getMTime()),
169 1
            'filepath' => $this->file->getRelativePathname(),
170
        ]);
171
        /*
172
         * Set specific variables
173
         */
174
        // is file has a prefix?
175 1
        if (PrefixSuffix::hasPrefix($fileName)) {
176 1
            $prefix = PrefixSuffix::getPrefix($fileName);
177 1
            if ($prefix !== null) {
178
                // prefix is a valid date?
179 1
                if (Util\Date::isValid($prefix)) {
180 1
                    $this->setVariable('date', (string) $prefix);
181
                } else {
182
                    // prefix is an integer: used for sorting
183 1
                    $this->setVariable('weight', (int) $prefix);
184
                }
185
            }
186
        }
187
        // is file has a language suffix?
188 1
        if (PrefixSuffix::hasSuffix($fileName)) {
189 1
            $this->setVariable('language', PrefixSuffix::getSuffix($fileName));
190
        }
191
        // set reference between page's translations, even if it exist in only one language
192 1
        $this->setVariable('langref', $this->getPath());
193
194 1
        return $this;
195
    }
196
197
    /**
198
     * Returns file real path.
199
     */
200 1
    public function getFilePath(): ?string
201
    {
202 1
        return $this->file->getRealPath() === false ? null : $this->file->getRealPath();
203
    }
204
205
    /**
206
     * Parse file content.
207
     */
208 1
    public function parse(): self
209
    {
210 1
        $parser = new Parser($this->file);
211 1
        $parsed = $parser->parse();
212 1
        $this->frontmatter = $parsed->getFrontmatter();
213 1
        $this->body = $parsed->getBody();
214
215 1
        return $this;
216
    }
217
218
    /**
219
     * Get frontmatter.
220
     */
221 1
    public function getFrontmatter(): ?string
222
    {
223 1
        return $this->frontmatter;
224
    }
225
226
    /**
227
     * Get body as raw.
228
     */
229 1
    public function getBody(): ?string
230
    {
231 1
        return $this->body;
232
    }
233
234
    /**
235
     * Set virtual status.
236
     */
237 1
    public function setVirtual(bool $virtual): self
238
    {
239 1
        $this->virtual = $virtual;
240
241 1
        return $this;
242
    }
243
244
    /**
245
     * Is current page is virtual?
246
     */
247 1
    public function isVirtual(): bool
248
    {
249 1
        return $this->virtual;
250
    }
251
252
    /**
253
     * Set page type.
254
     */
255 1
    public function setType(string $type): self
256
    {
257 1
        $this->type = new Type($type);
258
259 1
        return $this;
260
    }
261
262
    /**
263
     * Get page type.
264
     */
265 1
    public function getType(): string
266
    {
267 1
        return (string) $this->type;
268
    }
269
270
    /**
271
     * Set path without slug.
272
     */
273 1
    public function setFolder(string $folder): self
274
    {
275 1
        $this->folder = self::slugify($folder);
276
277 1
        return $this;
278
    }
279
280
    /**
281
     * Get path without slug.
282
     */
283 1
    public function getFolder(): ?string
284
    {
285 1
        return $this->folder;
286
    }
287
288
    /**
289
     * Set slug.
290
     */
291 1
    public function setSlug(string $slug): self
292
    {
293 1
        if (!$this->slug) {
294 1
            $slug = self::slugify(PrefixSuffix::sub($slug));
295
        }
296
        // force slug and update path
297 1
        if ($this->slug && $this->slug != $slug) {
298 1
            $this->setPath($this->getFolder().'/'.$slug);
299
        }
300 1
        $this->slug = $slug;
301
302 1
        return $this;
303
    }
304
305
    /**
306
     * Get slug.
307
     */
308 1
    public function getSlug(): string
309
    {
310 1
        return $this->slug;
311
    }
312
313
    /**
314
     * Set path.
315
     */
316 1
    public function setPath(string $path): self
317
    {
318 1
        $path = self::slugify(PrefixSuffix::sub($path));
319
320
        // case of homepage
321 1
        if ($path == 'index') {
322 1
            $this->path = '';
323
324 1
            return $this;
325
        }
326
327
        // case of custom sections' index (ie: content/section/index.md)
328 1
        if (substr($path, -6) == '/index') {
329 1
            $path = substr($path, 0, strlen($path) - 6);
330
        }
331 1
        $this->path = $path;
332
333
        // case of root pages
334 1
        $lastslash = strrpos($this->path, '/');
335 1
        if ($lastslash === false) {
336 1
            $this->slug = $this->path;
337
338 1
            return $this;
339
        }
340
341 1
        if (!$this->virtual && $this->getSection() === null) {
342 1
            $this->section = explode('/', $this->path)[0];
343
        }
344 1
        $this->folder = substr($this->path, 0, $lastslash);
345 1
        $this->slug = substr($this->path, -(strlen($this->path) - $lastslash - 1));
346
347 1
        return $this;
348
    }
349
350
    /**
351
     * Get path.
352
     */
353 1
    public function getPath(): ?string
354
    {
355 1
        return $this->path;
356
    }
357
358
    /**
359
     * @see getPath()
360
     */
361
    public function getPathname(): ?string
362
    {
363
        return $this->getPath();
364
    }
365
366
    /**
367
     * Set section.
368
     */
369 1
    public function setSection(string $section): self
370
    {
371 1
        $this->section = $section;
372
373 1
        return $this;
374
    }
375
376
    /**
377
     * Get section.
378
     */
379 1
    public function getSection(): ?string
380
    {
381 1
        return !empty($this->section) ? $this->section : null;
382
    }
383
384
    /**
385
     * Set body as HTML.
386
     */
387 1
    public function setBodyHtml(string $html): self
388
    {
389 1
        $this->html = $html;
390
391 1
        return $this;
392
    }
393
394
    /**
395
     * Get body as HTML.
396
     */
397 1
    public function getBodyHtml(): ?string
398
    {
399 1
        return $this->html;
400
    }
401
402
    /**
403
     * @see getBodyHtml()
404
     */
405 1
    public function getContent(): ?string
406
    {
407 1
        return $this->getBodyHtml();
408
    }
409
410
    /**
411
     * Set rendered.
412
     */
413 1
    public function setRendered(array $rendered): self
414
    {
415 1
        $this->rendered = $rendered;
416
417 1
        return $this;
418
    }
419
420
    /**
421
     * Get rendered.
422
     */
423 1
    public function getRendered(): array
424
    {
425 1
        return $this->rendered;
426
    }
427
428
    /**
429
     * Set Subpages.
430
     */
431 1
    public function setPages(\Cecil\Collection\Page\Collection $subPages): self
432
    {
433 1
        $this->subPages = $subPages;
434
435 1
        return $this;
436
    }
437
438
    /**
439
     * Get Subpages.
440
     */
441 1
    public function getPages(): ?\Cecil\Collection\Page\Collection
442
    {
443 1
        return $this->subPages;
444
    }
445
446
    /**
447
     * Set paginator.
448
     */
449 1
    public function setPaginator(array $paginator): self
450
    {
451 1
        $this->paginator = $paginator;
452
453 1
        return $this;
454
    }
455
456
    /**
457
     * Get paginator.
458
     */
459 1
    public function getPaginator(): array
460
    {
461 1
        return $this->paginator;
462
    }
463
464
    /**
465
     * Paginator backward compatibility.
466
     */
467 1
    public function getPagination(): array
468
    {
469 1
        return $this->getPaginator();
470
    }
471 1
472
    /**
473
     * Set vocabulary terms.
474
     */
475
    public function setTerms(\Cecil\Collection\Taxonomy\Vocabulary $terms): self
476
    {
477 1
        $this->terms = $terms;
478
479 1
        return $this;
480
    }
481
482
    /**
483
     * Get vocabulary terms.
484
     */
485
    public function getTerms(): \Cecil\Collection\Taxonomy\Vocabulary
486
    {
487
        return $this->terms;
488
    }
489
490
    /*
491 1
     * Helpers to set and get variables.
492
     */
493 1
494 1
    /**
495
     * Set an array as variables.
496
     *
497 1
     * @throws RuntimeException
498
     */
499
    public function setVariables(array $variables): self
500
    {
501
        foreach ($variables as $key => $value) {
502
            $this->setVariable($key, $value);
503 1
        }
504
505 1
        return $this;
506
    }
507
508
    /**
509
     * Get all variables.
510
     */
511
    public function getVariables(): array
512
    {
513
        return $this->properties;
514
    }
515
516 1
    /**
517
     * Set a variable.
518 1
     *
519
     * @param string $name  Name of the variable
520
     * @param mixed  $value Value of the variable
521
     *
522 1
     * @throws RuntimeException
523
     */
524
    public function setVariable(string $name, $value): self
525
    {
526 1
        $this->filterBool($value);
527 1
        /**
528
         * handle variable by its name.
529 1
         */
530
        switch ($name) {
531
            /**
532
             * date: 2012-10-08.
533 1
             */
534 1
            case 'date':
535
            case 'updated':
536
                try {
537
                    $date = Util\Date::toDatetime($value);
538
                } catch (\Exception $e) {
539
                    throw new \Exception(\sprintf('Expected date format for variable "%s" must be "YYYY-MM-DD" instead of "%s".', $name, (string) $value));
540 1
                }
541 1
                $this->offsetSet($name, $date);
542 1
                break;
543 1
            /**
544
             * schedule:
545
             *   publish: 2012-10-08
546 1
             *   expiry: 2012-10-09.
547
             */
548
            case 'schedule':
549
                $this->offsetSet('published', false);
550 1
                if (is_array($value)) {
551
                    if (array_key_exists('publish', $value) && Util\Date::toDatetime($value['publish']) <= Util\Date::toDatetime('now')) {
552
                        $this->offsetSet('published', true);
553
                    }
554 1
                    if (array_key_exists('expiry', $value) && Util\Date::toDatetime($value['expiry']) >= Util\Date::toDatetime('now')) {
555 1
                        $this->offsetSet('published', true);
556 1
                    }
557
                }
558 1
                break;
559
            /**
560
             * draft: true = published: false.
561
             */
562
            case 'draft':
563
                if ($value === true) {
564
                    $this->offsetSet('published', false);
565
                }
566
                break;
567 1
            /**
568 1
             * @see setPath()
569 1
             * @see setSlug()
570 1
             *
571
             * e.g.:
572
             *   path: about/about
573 1
             *   slug: about
574 1
             */
575 1
            case 'path':
576
            case 'slug':
577 1
                $slugify = self::slugify((string) $value);
578
                if ($value != $slugify) {
579
                    throw new RuntimeException(\sprintf('"%s" variable should be "%s" (not "%s") in "%s".', $name, $slugify, (string) $value, $this->getId()));
580 1
                }
581
                $method = 'set'.\ucfirst($name);
582
                $this->$method($value);
583
                break;
584
            default:
585
                $this->offsetSet($name, $value);
586
        }
587
588 1
        return $this;
589
    }
590 1
591
    /**
592
     * Is variable exists?
593
     *
594
     * @param string $name Name of the variable
595
     */
596
    public function hasVariable(string $name): bool
597
    {
598
        return $this->offsetExists($name);
599
    }
600
601 1
    /**
602
     * Get a variable.
603 1
     *
604 1
     * @param string     $name    Name of the variable
605
     * @param mixed|null $default Default value
606
     *
607 1
     * @return mixed|null
608
     */
609
    public function getVariable(string $name, $default = null)
610
    {
611
        if ($this->offsetExists($name)) {
612
            return $this->offsetGet($name);
613
        }
614
615 1
        return $default;
616
    }
617 1
618 1
    /**
619
     * Unset a variable.
620
     *
621 1
     * @param string $name Name of the variable
622
     */
623
    public function unVariable(string $name): self
624
    {
625
        if ($this->offsetExists($name)) {
626
            $this->offsetUnset($name);
627 1
        }
628
629 1
        return $this;
630
    }
631 1
632
    /**
633
     * Set front matter (only) variables.
634
     */
635
    public function setFmVariables(array $variables): self
636
    {
637 1
        $this->fmVariables = $variables;
638
639 1
        return $this;
640
    }
641
642
    /**
643
     * Get front matter variables.
644
     */
645
    public function getFmVariables(): array
646
    {
647
        return $this->fmVariables;
648
    }
649
650
    /**
651 1
     * Cast "boolean" string (or array of strings) to boolean.
652
     *
653 1
     * @param mixed $value Value to filter
654 1
     *
655 1
     * @return bool|mixed
656
     *
657
     * @see strToBool()
658
     */
659
    private function filterBool(&$value)
660
    {
661
        \Cecil\Util\Str::strToBool($value);
662
        if (is_array($value)) {
663
            array_walk_recursive($value, '\Cecil\Util\Str::strToBool');
664
        }
665
    }
666
}
667