Passed
Pull Request — 6 (#1291)
by Arnaud
08:00 queued 11s
created

Page::setVariable()   B

Complexity

Conditions 10
Paths 18

Size

Total Lines 35
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 15.9914

Importance

Changes 0
Metric Value
cc 10
eloc 25
c 0
b 0
f 0
nc 18
nop 2
dl 0
loc 35
ccs 14
cts 23
cp 0.6087
crap 15.9914
rs 7.6666

How to fix   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
 * This file is part of the Cecil/Cecil package.
4
 *
5
 * Copyright (c) Arnaud Ligny <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
declare(strict_types=1);
12
13
namespace Cecil\Collection\Page;
14
15
use Cecil\Collection\Item;
16
use Cecil\Exception\RuntimeException;
17
use Cecil\Util;
18
use Cocur\Slugify\Slugify;
19
use Symfony\Component\Finder\SplFileInfo;
20
21
/**
22
 * Class Page.
23
 */
24
class Page extends Item
25
{
26
    const SLUGIFY_PATTERN = '/(^\/|[^._a-z0-9\/]|-)+/'; // should be '/^\/|[^_a-z0-9\/]+/'
27
28
    /** @var bool True if page is not created from a Markdown file. */
29
    protected $virtual;
30
31
    /** @var SplFileInfo */
32
    protected $file;
33
34
    /** @var string Homepage, Page, Section, etc. */
35
    protected $type;
36
37
    /** @var string */
38
    protected $folder;
39
40
    /** @var string */
41
    protected $slug;
42
43
    /** @var string folder + slug. */
44
    protected $path;
45
46
    /** @var string */
47
    protected $section;
48
49
    /** @var string */
50
    protected $frontmatter;
51
52
    /** @var string Body before conversion. */
53
    protected $body;
54
55
    /** @var array Front matter before conversion. */
56
    protected $fmVariables = [];
57
58
    /** @var string Body after Markdown conversion. */
59
    protected $html;
60
61
    /** @var Slugify */
62
    private static $slugifier;
63 1
64
    public function __construct(string $id)
65 1
    {
66 1
        parent::__construct($id);
67 1
        $this->setVirtual(true);
68
        $this->setType(Type::PAGE);
69 1
        // default variables
70 1
        $this->setVariables([
71 1
            'title'            => 'Page Title',
72 1
            'date'             => new \DateTime(),
73
            'updated'          => new \DateTime(),
74
            'weight'           => null,
75
            'filepath'         => null,
76 1
            'published'        => true,
77
            'content_template' => 'page.content.twig',
78 1
        ]);
79
    }
80
81
    /**
82
     * Turns a path (string) into a slug (URI).
83 1
     */
84
    public static function slugify(string $path): string
85 1
    {
86 1
        if (!self::$slugifier instanceof Slugify) {
87
            self::$slugifier = Slugify::create(['regexp' => self::SLUGIFY_PATTERN]);
88
        }
89 1
90
        return self::$slugifier->slugify($path);
91
    }
92
93
    /**
94
     * Creates the ID from the file path.
95 1
     */
96
    public static function createId(SplFileInfo $file): string
97 1
    {
98 1
        $relativepath = self::slugify(str_replace(DIRECTORY_SEPARATOR, '/', $file->getRelativePath()));
99
        $basename = self::slugify(PrefixSuffix::subPrefix($file->getBasename('.'.$file->getExtension())));
100 1
        // case of "README" -> index
101
        $basename = (string) str_ireplace('readme', 'index', $basename);
102 1
        // case of section's index: "section/index" -> "section"
103
        if (!empty($relativepath) && PrefixSuffix::sub($basename) == 'index') {
104 1
            // case of a localized section
105
            if (PrefixSuffix::hasSuffix($basename)) {
106
                return $relativepath.'.'.PrefixSuffix::getSuffix($basename);
107
            }
108 1
109
            return $relativepath;
110
        }
111 1
112
        return trim(Util::joinPath($relativepath, $basename), '/');
113
    }
114
115
    /**
116
     * Returns the ID of a page without language suffix.
117 1
     */
118
    public function getIdWithoutLang(): string
119 1
    {
120
        return PrefixSuffix::sub($this->getId());
121
    }
122
123
    /**
124
     * Set file.
125 1
     */
126
    public function setFile(SplFileInfo $file): self
127 1
    {
128 1
        $this->setVirtual(false);
129
        $this->file = $file;
130
131
        /*
132
         * File path components
133 1
         */
134 1
        $fileRelativePath = str_replace(DIRECTORY_SEPARATOR, '/', $this->file->getRelativePath());
135 1
        $fileExtension = $this->file->getExtension();
136
        $fileName = $this->file->getBasename('.'.$fileExtension);
137 1
        // case of "README" -> "index"
138
        $fileName = (string) str_ireplace('readme', 'index', $fileName);
139 1
        // case of "index" = home page
140 1
        if (empty($this->file->getRelativePath()) && PrefixSuffix::sub($fileName) == 'index') {
141
            $this->setType(Type::HOMEPAGE);
142
        }
143
        /*
144
         * Set protected variables
145 1
         */
146 1
        $this->setFolder($fileRelativePath); // ie: "blog"
147 1
        $this->setSlug($fileName); // ie: "post-1"
148
        $this->setPath($this->getFolder().'/'.$this->getSlug()); // ie: "blog/post-1"
149
        /*
150
         * Set default variables
151 1
         */
152 1
        $this->setVariables([
153 1
            'title'    => PrefixSuffix::sub($fileName),
154 1
            'date'     => (new \DateTime())->setTimestamp($this->file->getCTime()),
155 1
            'updated'  => (new \DateTime())->setTimestamp($this->file->getMTime()),
156
            'filepath' => $this->file->getRelativePathname(),
157
        ]);
158
        /*
159
         * Set specific variables
160
         */
161 1
        // is file has a prefix?
162 1
        if (PrefixSuffix::hasPrefix($fileName)) {
163 1
            $prefix = PrefixSuffix::getPrefix($fileName);
164
            if ($prefix !== null) {
165 1
                // prefix is a valid date?
166 1
                if (Util\Date::isDateValid($prefix)) {
167
                    $this->setVariable('date', (string) $prefix);
168
                } else {
169 1
                    // prefix is an integer: used for sorting
170
                    $this->setVariable('weight', (int) $prefix);
171
                }
172
            }
173
        }
174 1
        // is file has a language suffix?
175 1
        if (PrefixSuffix::hasSuffix($fileName)) {
176
            $this->setVariable('language', PrefixSuffix::getSuffix($fileName));
177
        }
178 1
        // set reference between translations
179
        $this->setVariable('langref', $this->getPath());
180 1
181
        return $this;
182
    }
183
184
    /**
185
     * Returns file real path.
186 1
     */
187
    public function getFilePath(): ?string
188 1
    {
189 1
        return $this->file->getRealPath() === false ? null : $this->file->getRealPath();
190 1
    }
191 1
192
    /**
193 1
     * Parse file content.
194
     */
195
    public function parse(): self
196
    {
197
        $parser = new Parser($this->file);
198
        $parsed = $parser->parse();
199 1
        $this->frontmatter = $parsed->getFrontmatter();
200
        $this->body = $parsed->getBody();
201 1
202
        return $this;
203
    }
204
205
    /**
206
     * Get frontmatter.
207 1
     */
208
    public function getFrontmatter(): ?string
209 1
    {
210
        return $this->frontmatter;
211
    }
212
213
    /**
214
     * Get body as raw.
215 1
     */
216
    public function getBody(): ?string
217 1
    {
218
        return $this->body;
219 1
    }
220
221
    /**
222
     * Set virtual status.
223
     */
224
    public function setVirtual(bool $virtual): self
225 1
    {
226
        $this->virtual = $virtual;
227 1
228
        return $this;
229
    }
230
231
    /**
232
     * Is current page is virtual?
233 1
     */
234
    public function isVirtual(): bool
235 1
    {
236
        return $this->virtual;
237 1
    }
238
239
    /**
240
     * Set page type.
241
     */
242
    public function setType(string $type): self
243 1
    {
244
        $this->type = new Type($type);
245 1
246
        return $this;
247
    }
248
249
    /**
250
     * Get page type.
251 1
     */
252
    public function getType(): string
253 1
    {
254
        return (string) $this->type;
255 1
    }
256
257
    /**
258
     * Set path without slug.
259
     */
260
    public function setFolder(string $folder): self
261 1
    {
262
        $this->folder = self::slugify($folder);
263 1
264
        return $this;
265
    }
266
267
    /**
268
     * Get path without slug.
269 1
     */
270
    public function getFolder(): ?string
271 1
    {
272 1
        return $this->folder;
273
    }
274
275 1
    /**
276 1
     * Set slug.
277
     */
278 1
    public function setSlug(string $slug): self
279
    {
280 1
        if (!$this->slug) {
281
            $slug = self::slugify(PrefixSuffix::sub($slug));
282
        }
283
        // force slug and update path
284
        if ($this->slug && $this->slug != $slug) {
285
            $this->setPath($this->getFolder().'/'.$slug);
286 1
        }
287
        $this->slug = $slug;
288 1
289
        return $this;
290
    }
291
292
    /**
293
     * Get slug.
294 1
     */
295
    public function getSlug(): string
296 1
    {
297
        return $this->slug;
298
    }
299 1
300 1
    /**
301
     * Set path.
302 1
     */
303
    public function setPath(string $path): self
304
    {
305
        $path = self::slugify(PrefixSuffix::sub($path));
306 1
307 1
        // case of homepage
308
        if ($path == 'index') {
309 1
            $this->path = '';
310
311
            return $this;
312 1
        }
313 1
314 1
        // case of custom sections' index (ie: content/section/index.md)
315
        if (substr($path, -6) == '/index') {
316 1
            $path = substr($path, 0, strlen($path) - 6);
317
        }
318
        $this->path = $path;
319 1
320 1
        // case of root pages
321
        $lastslash = strrpos($this->path, '/');
322 1
        if ($lastslash === false) {
323 1
            $this->slug = $this->path;
324
325 1
            return $this;
326
        }
327
328
        if (!$this->virtual && $this->getSection() === null) {
329
            $this->section = explode('/', $this->path)[0];
330
        }
331 1
        $this->folder = substr($this->path, 0, $lastslash);
332
        $this->slug = substr($this->path, -(strlen($this->path) - $lastslash - 1));
333 1
334
        return $this;
335
    }
336
337
    /**
338
     * Get path.
339
     */
340
    public function getPath(): ?string
341
    {
342
        return $this->path;
343
    }
344
345
    /**
346
     * @see getPath()
347 1
     */
348
    public function getPathname(): ?string
349 1
    {
350
        return $this->getPath();
351 1
    }
352
353
    /**
354
     * Set section.
355
     */
356
    public function setSection(string $section): self
357 1
    {
358
        $this->section = $section;
359 1
360
        return $this;
361
    }
362
363
    /**
364
     * Get section.
365 1
     */
366
    public function getSection(): ?string
367 1
    {
368
        return !empty($this->section) ? $this->section : null;
369 1
    }
370
371
    /**
372
     * Set body as HTML.
373
     */
374
    public function setBodyHtml(string $html): self
375 1
    {
376
        $this->html = $html;
377 1
378
        return $this;
379
    }
380
381
    /**
382
     * Get body as HTML.
383 1
     */
384
    public function getBodyHtml(): ?string
385 1
    {
386
        return $this->html;
387
    }
388
389
    /**
390
     * @see getBodyHtml()
391
     */
392
    public function getContent(): ?string
393
    {
394
        return $this->getBodyHtml();
395
    }
396
397 1
    /*
398
     * Helpers to set and get variables.
399 1
     */
400 1
401
    /**
402
     * Set an array as variables.
403 1
     *
404
     * @throws RuntimeException
405
     */
406
    public function setVariables(array $variables): self
407
    {
408
        foreach ($variables as $key => $value) {
409 1
            $this->setVariable($key, $value);
410
        }
411 1
412
        return $this;
413
    }
414
415
    /**
416
     * Get all variables.
417
     */
418
    public function getVariables(): array
419
    {
420
        return $this->properties;
421
    }
422 1
423
    /**
424 1
     * Set a variable.
425 1
     *
426
     * @param string $name
427 1
     * @param mixed  $value
428 1
     *
429
     * @throws RuntimeException
430 1
     */
431
    public function setVariable(string $name, $value): self
432
    {
433
        if (is_bool($value)) {
434
            $value = $value ?: 0;
435
        }
436
        switch ($name) {
437
            case 'date':
438 1
                try {
439 1
                    $date = Util\Date::dateToDatetime($value);
440 1
                } catch (\Exception $e) {
441 1
                    throw new RuntimeException(\sprintf('Expected date format (ie: "2012-10-08") for "date" in "%s" instead of "%s"', $this->getId(), (string) $value));
442 1
                }
443
                $this->offsetSet('date', $date);
444 1
                break;
445 1
            case 'draft':
446 1
                if ($value === true) {
447 1
                    $this->offsetSet('published', false);
448 1
                }
449
                break;
450
            case 'path':
451
            case 'slug':
452
                $slugify = self::slugify((string) $value);
453
                if ($value != $slugify) {
454
                    throw new RuntimeException(\sprintf('"%s" variable should be "%s" (not "%s") in "%s"', $name, $slugify, (string) $value, $this->getId()));
455
                }
456
                /** @see setPath() */
457
                /** @see setSlug() */
458
                $method = 'set'.\ucfirst($name);
459 1
                $this->$method($value);
460 1
                break;
461 1
            default:
462
                $this->offsetSet($name, $value);
463 1
        }
464
465
        return $this;
466 1
    }
467
468
    /**
469
     * Is variable exists?
470
     */
471
    public function hasVariable(string $name): bool
472 1
    {
473
        return $this->offsetExists($name);
474 1
    }
475
476
    /**
477
     * Get a variable.
478
     *
479
     * @return mixed|null
480
     */
481
    public function getVariable(string $name)
482 1
    {
483
        if ($this->offsetExists($name)) {
484 1
            return $this->offsetGet($name);
485 1
        }
486
    }
487 1
488
    /**
489
     * Unset a variable.
490
     */
491
    public function unVariable(string $name): self
492 1
    {
493
        if ($this->offsetExists($name)) {
494 1
            $this->offsetUnset($name);
495 1
        }
496
497
        return $this;
498 1
    }
499
500
    /**
501
     * Set front matter (only) variables.
502
     */
503
    public function setFmVariables(array $variables): self
504 1
    {
505
        $this->fmVariables = $variables;
506 1
507
        return $this;
508 1
    }
509
510
    /**
511
     * Get front matter variables.
512
     */
513
    public function getFmVariables(): array
514 1
    {
515
        return $this->fmVariables;
516 1
    }
517
}
518