Passed
Pull Request — master (#2148)
by Arnaud
10:28 queued 04:55
created

Builder::getRenderer()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
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;
15
16
use Cecil\Collection\Page\Collection as PagesCollection;
17
use Cecil\Exception\RuntimeException;
18
use Cecil\Generator\GeneratorManager;
19
use Cecil\Logger\PrintLogger;
20
use Psr\Log\LoggerAwareInterface;
21
use Psr\Log\LoggerInterface;
22
use Symfony\Component\Finder\Finder;
23
24
/**
25
 * Class Builder.
26
 */
27
class Builder implements LoggerAwareInterface
28
{
29
    public const VERSION = '8.x-dev';
30
    public const VERBOSITY_QUIET = -1;
31
    public const VERBOSITY_NORMAL = 0;
32
    public const VERBOSITY_VERBOSE = 1;
33
    public const VERBOSITY_DEBUG = 2;
34
35
    /**
36
     * @var array Steps processed by build().
37
     */
38
    protected $steps = [
39
        'Cecil\Step\Pages\Load',
40
        'Cecil\Step\Data\Load',
41
        'Cecil\Step\StaticFiles\Load',
42
        'Cecil\Step\Pages\Create',
43
        'Cecil\Step\Pages\Convert',
44
        'Cecil\Step\Taxonomies\Create',
45
        'Cecil\Step\Pages\Generate',
46
        'Cecil\Step\Menus\Create',
47
        'Cecil\Step\StaticFiles\Copy',
48
        'Cecil\Step\Pages\Render',
49
        'Cecil\Step\Pages\Save',
50
        'Cecil\Step\Assets\Save',
51
        'Cecil\Step\Optimize\Html',
52
        'Cecil\Step\Optimize\Css',
53
        'Cecil\Step\Optimize\Js',
54
        'Cecil\Step\Optimize\Images',
55
    ];
56
57
    /** @var Config Configuration. */
58
    protected $config;
59
60
    /** @var LoggerInterface Logger. */
61
    protected $logger;
62
63
    /** @var bool Debug mode. */
64
    protected $debug = false;
65
66
    /** @var array Build options. */
67
    protected $options;
68
69
    /** @var Finder Content iterator. */
70
    protected $content;
71
72
    /** @var array Data collection. */
73
    protected $data = [];
74
75
    /** @var array Static files collection. */
76
    protected $static = [];
77
78
    /** @var PagesCollection Pages collection. */
79
    protected $pages;
80
81
    /** @var array Assets path collection */
82
    protected $assets = [];
83
84
    /** @var array Menus collection. */
85
    protected $menus;
86
87
    /** @var array Taxonomies collection. */
88
    protected $taxonomies;
89
90
    /** @var Renderer\RendererInterface Renderer. */
91
    protected $renderer;
92
93
    /** @var GeneratorManager Generators manager. */
94
    protected $generatorManager;
95
96
    /** @var string Application version. */
97
    protected static $version;
98
99
    /** @var array Build metrics. */
100
    protected $metrics = [];
101
102
    /**
103
     * @param Config|array|null    $config
104
     * @param LoggerInterface|null $logger
105
     */
106 1
    public function __construct($config = null, ?LoggerInterface $logger = null)
107
    {
108
        // set config?
109 1
        if ($config !== null) {
110 1
            $this->setConfig($config);
111
        }
112
        // debug mode?
113 1
        if (getenv('CECIL_DEBUG') == 'true' || $this->getConfig()->isEnabled('debug')) {
114 1
            $this->debug = true;
115
        }
116
        // set logger
117 1
        if ($logger === null) {
118
            $logger = new PrintLogger(self::VERBOSITY_VERBOSE);
119
        }
120 1
        $this->setLogger($logger);
121
        // autoloads local extensions
122 1
        Util::autoload($this, 'extensions');
123
    }
124
125
    /**
126
     * Creates a new Builder instance.
127
     */
128 1
    public static function create(): self
129
    {
130 1
        $class = new \ReflectionClass(\get_called_class());
131
132 1
        return $class->newInstanceArgs(\func_get_args());
133
    }
134
135
    /**
136
     * Builds a new website.
137
     */
138 1
    public function build(array $options): self
139
    {
140
        // set start script time and memory usage
141 1
        $startTime = microtime(true);
142 1
        $startMemory = memory_get_usage();
143
144
        // log configuration errors
145 1
        $this->logConfigError();
146
147
        // prepare options
148 1
        $this->options = array_merge([
149 1
            'drafts'  => false, // build drafts or not
150 1
            'dry-run' => false, // if dry-run is true, generated files are not saved
151 1
            'page'    => '',    // specific page to build
152 1
        ], $options);
153
154
        // process each step
155 1
        $steps = [];
156
        // init...
157 1
        foreach ($this->steps as $step) {
158
            /** @var Step\StepInterface $stepObject */
159 1
            $stepObject = new $step($this);
160 1
            $stepObject->init($this->options);
161 1
            if ($stepObject->canProcess()) {
162 1
                $steps[] = $stepObject;
163
            }
164
        }
165
        // ...and process!
166 1
        $stepNumber = 0;
167 1
        $stepsTotal = \count($steps);
168 1
        foreach ($steps as $step) {
169 1
            $stepNumber++;
170
            /** @var Step\StepInterface $step */
171 1
            $this->getLogger()->notice($step->getName(), ['step' => [$stepNumber, $stepsTotal]]);
172 1
            $stepStartTime = microtime(true);
173 1
            $stepStartMemory = memory_get_usage();
174 1
            $step->process();
175
            // step duration and memory usage
176 1
            $this->metrics['steps'][$stepNumber]['name'] = $step->getName();
177 1
            $this->metrics['steps'][$stepNumber]['duration'] = Util::convertMicrotime((float) $stepStartTime);
178 1
            $this->metrics['steps'][$stepNumber]['memory']   = Util::convertMemory(memory_get_usage() - $stepStartMemory);
179 1
            $this->getLogger()->info(\sprintf(
180 1
                '%s done in %s (%s)',
181 1
                $this->metrics['steps'][$stepNumber]['name'],
182 1
                $this->metrics['steps'][$stepNumber]['duration'],
183 1
                $this->metrics['steps'][$stepNumber]['memory']
184 1
            ));
185
        }
186
        // build duration and memory usage
187 1
        $this->metrics['total']['duration'] = Util::convertMicrotime($startTime);
0 ignored issues
show
Bug introduced by
It seems like $startTime can also be of type string; however, parameter $start of Cecil\Util::convertMicrotime() does only seem to accept double, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

187
        $this->metrics['total']['duration'] = Util::convertMicrotime(/** @scrutinizer ignore-type */ $startTime);
Loading history...
188 1
        $this->metrics['total']['memory']   = Util::convertMemory(memory_get_usage() - $startMemory);
189 1
        $this->getLogger()->notice(\sprintf('Built in %s (%s)', $this->metrics['total']['duration'], $this->metrics['total']['memory']));
190
191 1
        return $this;
192
    }
193
194
    /**
195
     * Set configuration.
196
     */
197 1
    public function setConfig(array|Config $config): self
198
    {
199 1
        if (!$config instanceof Config) {
0 ignored issues
show
introduced by
$config is never a sub-type of Cecil\Config.
Loading history...
200 1
            $config = new Config($config);
201
        }
202 1
        if ($this->config !== $config) {
203 1
            $this->config = $config;
204
        }
205
206 1
        return $this;
207
    }
208
209
    /**
210
     * Returns configuration.
211
     */
212 1
    public function getConfig(): Config
213
    {
214 1
        if ($this->config === null) {
215
            $this->config = new Config();
216
        }
217
218 1
        return $this->config;
219
    }
220
221
    /**
222
     * Config::setSourceDir() alias.
223
     */
224 1
    public function setSourceDir(string $sourceDir): self
225
    {
226 1
        $this->config->setSourceDir($sourceDir);
227
228 1
        return $this;
229
    }
230
231
    /**
232
     * Config::setDestinationDir() alias.
233
     */
234 1
    public function setDestinationDir(string $destinationDir): self
235
    {
236 1
        $this->config->setDestinationDir($destinationDir);
237
238 1
        return $this;
239
    }
240
241
    /**
242
     * {@inheritdoc}
243
     */
244 1
    public function setLogger(LoggerInterface $logger): void
245
    {
246 1
        $this->logger = $logger;
247
    }
248
249
    /**
250
     * Returns the logger instance.
251
     */
252 1
    public function getLogger(): LoggerInterface
253
    {
254 1
        return $this->logger;
255
    }
256
257
    /**
258
     * Returns debug mode state.
259
     */
260 1
    public function isDebug(): bool
261
    {
262 1
        return (bool) $this->debug;
263
    }
264
265
    /**
266
     * Returns build options.
267
     */
268 1
    public function getBuildOptions(): array
269
    {
270 1
        return $this->options;
271
    }
272
273
    /**
274
     * Set collected pages files.
275
     */
276 1
    public function setPagesFiles(Finder $content): void
277
    {
278 1
        $this->content = $content;
279
    }
280
281
    /**
282
     * Returns pages files.
283
     */
284 1
    public function getPagesFiles(): ?Finder
285
    {
286 1
        return $this->content;
287
    }
288
289
    /**
290
     * Set collected data.
291
     */
292 1
    public function setData(array $data): void
293
    {
294 1
        $this->data = $data;
295
    }
296
297
    /**
298
     * Returns data collection.
299
     */
300 1
    public function getData(?string $language = null): ?array
301
    {
302 1
        if ($language) {
303 1
            if (empty($this->data[$language])) {
304
                // fallback to default language
305 1
                return $this->data[$this->config->getLanguageDefault()];
306
            }
307
308 1
            return $this->data[$language];
309
        }
310
311 1
        return $this->data;
312
    }
313
314
    /**
315
     * Set collected static files.
316
     */
317 1
    public function setStatic(array $static): void
318
    {
319 1
        $this->static = $static;
320
    }
321
322
    /**
323
     * Returns static files collection.
324
     */
325 1
    public function getStatic(): array
326
    {
327 1
        return $this->static;
328
    }
329
330
    /**
331
     * Set/update Pages collection.
332
     */
333 1
    public function setPages(PagesCollection $pages): void
334
    {
335 1
        $this->pages = $pages;
336
    }
337
338
    /**
339
     * Returns pages collection.
340
     */
341 1
    public function getPages(): ?PagesCollection
342
    {
343 1
        return $this->pages;
344
    }
345
346
    /**
347
     * Set assets path collection.
348
     */
349
    public function setAssets(array $assets): void
350
    {
351
        $this->assets = $assets;
352
    }
353
354
    /**
355
     * Add an asset path to assets collection.
356
     */
357 1
    public function addAsset(string $path): void
358
    {
359 1
        if (!\in_array($path, $this->assets, true)) {
360 1
            $this->assets[] = $path;
361
        }
362
    }
363
364
    /**
365
     * Returns list of assets path.
366
     */
367 1
    public function getAssets(): ?array
368
    {
369 1
        return $this->assets;
370
    }
371
372
    /**
373
     * Set menus collection.
374
     */
375 1
    public function setMenus(array $menus): void
376
    {
377 1
        $this->menus = $menus;
378
    }
379
380
    /**
381
     * Returns all menus, for a language.
382
     */
383 1
    public function getMenus(string $language): Collection\Menu\Collection
384
    {
385 1
        return $this->menus[$language];
386
    }
387
388
    /**
389
     * Set taxonomies collection.
390
     */
391 1
    public function setTaxonomies(array $taxonomies): void
392
    {
393 1
        $this->taxonomies = $taxonomies;
394
    }
395
396
    /**
397
     * Returns taxonomies collection, for a language.
398
     */
399 1
    public function getTaxonomies(string $language): ?Collection\Taxonomy\Collection
400
    {
401 1
        return $this->taxonomies[$language];
402
    }
403
404
    /**
405
     * Set renderer object.
406
     */
407 1
    public function setRenderer(Renderer\RendererInterface $renderer): void
408
    {
409 1
        $this->renderer = $renderer;
410
    }
411
412
    /**
413
     * Returns Renderer object.
414
     */
415 1
    public function getRenderer(): Renderer\RendererInterface
416
    {
417 1
        return $this->renderer;
418
    }
419
420
    /**
421
     * Returns metrics array.
422
     */
423
    public function getMetrics(): array
424
    {
425
        return $this->metrics;
426
    }
427
428
    /**
429
     * Returns application version.
430
     *
431
     * @throws RuntimeException
432
     */
433 1
    public static function getVersion(): string
434
    {
435 1
        if (!isset(self::$version)) {
436
            try {
437 1
                $filePath = Util\File::getRealPath('VERSION');
438
                $version = Util\File::fileGetContents($filePath);
439
                if ($version === false) {
440
                    throw new RuntimeException(\sprintf('Can\'t read content of "%s".', $filePath));
441
                }
442
                self::$version = trim($version);
443 1
            } catch (\Exception) {
444 1
                self::$version = self::VERSION;
445
            }
446
        }
447
448 1
        return self::$version;
449
    }
450
451
    /**
452
     * Log configuration errors.
453
     */
454 1
    protected function logConfigError(): void
455
    {
456
        // warning about baseurl
457 1
        if (empty(trim((string) $this->config->get('baseurl'), '/'))) {
458
            $this->getLogger()->warning('`baseurl` configuration key is required in production.');
459
        }
460
    }
461
}
462