• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Cecilapp / Cecil / 14084198039

26 Mar 2025 01:13PM UTC coverage: 82.053% (-0.02%) from 82.07%
14084198039

push

github

ArnaudLigny
refactor: testing getRealPath

4 of 6 new or added lines in 1 file covered. (66.67%)

4 existing lines in 1 file now uncovered.

2958 of 3605 relevant lines covered (82.05%)

0.82 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.3
/src/Builder.php
1
<?php
2

3
declare(strict_types=1);
4

5
/*
6
 * This file is part of Cecil.
7
 *
8
 * Copyright (c) Arnaud Ligny <arnaud@ligny.fr>
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 Cecil\Util\Platform;
21
use Psr\Log\LoggerAwareInterface;
22
use Psr\Log\LoggerInterface;
23
use Symfony\Component\Finder\Finder;
24

25
/**
26
 * Class Builder.
27
 */
28
class Builder implements LoggerAwareInterface
29
{
30
    public const VERSION = '8.x-dev';
31
    public const VERBOSITY_QUIET = -1;
32
    public const VERBOSITY_NORMAL = 0;
33
    public const VERBOSITY_VERBOSE = 1;
34
    public const VERBOSITY_DEBUG = 2;
35

36
    /**
37
     * @var array Steps processed by build().
38
     */
39
    protected $steps = [
40
        'Cecil\Step\Pages\Load',
41
        'Cecil\Step\Data\Load',
42
        'Cecil\Step\StaticFiles\Load',
43
        'Cecil\Step\Pages\Create',
44
        'Cecil\Step\Pages\Convert',
45
        'Cecil\Step\Taxonomies\Create',
46
        'Cecil\Step\Pages\Generate',
47
        'Cecil\Step\Menus\Create',
48
        'Cecil\Step\StaticFiles\Copy',
49
        'Cecil\Step\Pages\Render',
50
        'Cecil\Step\Pages\Save',
51
        'Cecil\Step\Assets\Save',
52
        'Cecil\Step\Optimize\Html',
53
        'Cecil\Step\Optimize\Css',
54
        'Cecil\Step\Optimize\Js',
55
        'Cecil\Step\Optimize\Images',
56
    ];
57

58
    /** @var Config Configuration. */
59
    protected $config;
60

61
    /** @var LoggerInterface Logger. */
62
    protected $logger;
63

64
    /** @var bool Debug mode. */
65
    protected $debug = false;
66

67
    /** @var array Build options. */
68
    protected $options;
69

70
    /** @var Finder Content iterator. */
71
    protected $content;
72

73
    /** @var array Data collection. */
74
    protected $data = [];
75

76
    /** @var array Static files collection. */
77
    protected $static = [];
78

79
    /** @var PagesCollection Pages collection. */
80
    protected $pages;
81

82
    /** @var array Assets path collection */
83
    protected $assets = [];
84

85
    /** @var array Menus collection. */
86
    protected $menus;
87

88
    /** @var array Taxonomies collection. */
89
    protected $taxonomies;
90

91
    /** @var Renderer\RendererInterface Renderer. */
92
    protected $renderer;
93

94
    /** @var GeneratorManager Generators manager. */
95
    protected $generatorManager;
96

97
    /** @var string Application version. */
98
    protected static $version;
99

100
    /** @var array Build metrics. */
101
    protected $metrics = [];
102

103
    /**
104
     * @param Config|array|null    $config
105
     * @param LoggerInterface|null $logger
106
     */
107
    public function __construct($config = null, ?LoggerInterface $logger = null)
108
    {
109
        // set logger
110
        if ($logger === null) {
1✔
111
            $logger = new PrintLogger(self::VERBOSITY_VERBOSE);
×
112
        }
113
        $this->setLogger($logger);
1✔
114
        // set config
115
        $this->setConfig($config)->setSourceDir(null)->setDestinationDir(null);
1✔
116
        // debug mode?
117
        if (getenv('CECIL_DEBUG') == 'true' || (bool) $this->getConfig()->get('debug')) {
1✔
118
            $this->debug = true;
1✔
119
        }
120
        // autoloads local extensions
121
        Util::autoload($this, 'extensions');
1✔
122
    }
123

124
    /**
125
     * Creates a new Builder instance.
126
     */
127
    public static function create(): self
128
    {
129
        $class = new \ReflectionClass(\get_called_class());
1✔
130

131
        return $class->newInstanceArgs(\func_get_args());
1✔
132
    }
133

134
    /**
135
     * Builds a new website.
136
     */
137
    public function build(array $options): self
138
    {
139
        // set start script time and memory usage
140
        $startTime = microtime(true);
1✔
141
        $startMemory = memory_get_usage();
1✔
142

143
        // log configuration errors
144
        $this->logConfigError();
1✔
145

146
        // prepare options
147
        $this->options = array_merge([
1✔
148
            'drafts'  => false, // build drafts or not
1✔
149
            'dry-run' => false, // if dry-run is true, generated files are not saved
1✔
150
            'page'    => '',    // specific page to build
1✔
151
        ], $options);
1✔
152

153
        // process each step
154
        $steps = [];
1✔
155
        // init...
156
        foreach ($this->steps as $step) {
1✔
157
            /** @var Step\StepInterface $stepObject */
158
            $stepObject = new $step($this);
1✔
159
            $stepObject->init($this->options);
1✔
160
            if ($stepObject->canProcess()) {
1✔
161
                $steps[] = $stepObject;
1✔
162
            }
163
        }
164
        // ...and process!
165
        $stepNumber = 0;
1✔
166
        $stepsTotal = \count($steps);
1✔
167
        foreach ($steps as $step) {
1✔
168
            $stepNumber++;
1✔
169
            /** @var Step\StepInterface $step */
170
            $this->getLogger()->notice($step->getName(), ['step' => [$stepNumber, $stepsTotal]]);
1✔
171
            $stepStartTime = microtime(true);
1✔
172
            $stepStartMemory = memory_get_usage();
1✔
173
            $step->process();
1✔
174
            // step duration and memory usage
175
            $this->metrics['steps'][$stepNumber]['name'] = $step->getName();
1✔
176
            $this->metrics['steps'][$stepNumber]['duration'] = Util::convertMicrotime((float) $stepStartTime);
1✔
177
            $this->metrics['steps'][$stepNumber]['memory']   = Util::convertMemory(memory_get_usage() - $stepStartMemory);
1✔
178
            $this->getLogger()->info(\sprintf(
1✔
179
                '%s done in %s (%s)',
1✔
180
                $this->metrics['steps'][$stepNumber]['name'],
1✔
181
                $this->metrics['steps'][$stepNumber]['duration'],
1✔
182
                $this->metrics['steps'][$stepNumber]['memory']
1✔
183
            ));
1✔
184
        }
185
        // build duration and memory usage
186
        $this->metrics['total']['duration'] = Util::convertMicrotime($startTime);
1✔
187
        $this->metrics['total']['memory']   = Util::convertMemory(memory_get_usage() - $startMemory);
1✔
188
        $this->getLogger()->notice(\sprintf('Built in %s (%s)', $this->metrics['total']['duration'], $this->metrics['total']['memory']));
1✔
189

190
        return $this;
1✔
191
    }
192

193
    /**
194
     * Set configuration.
195
     *
196
     * @param Config|array|null $config
197
     */
198
    public function setConfig($config): self
199
    {
200
        if (!$config instanceof Config) {
1✔
201
            $config = new Config($config);
1✔
202
        }
203
        if ($this->config !== $config) {
1✔
204
            $this->config = $config;
1✔
205
        }
206

207
        return $this;
1✔
208
    }
209

210
    /**
211
     * Returns configuration.
212
     */
213
    public function getConfig(): Config
214
    {
215
        return $this->config;
1✔
216
    }
217

218
    /**
219
     * Config::setSourceDir() alias.
220
     */
221
    public function setSourceDir(?string $sourceDir = null): self
222
    {
223
        $this->config->setSourceDir($sourceDir);
1✔
224

225
        return $this;
1✔
226
    }
227

228
    /**
229
     * Config::setDestinationDir() alias.
230
     */
231
    public function setDestinationDir(?string $destinationDir = null): self
232
    {
233
        $this->config->setDestinationDir($destinationDir);
1✔
234

235
        return $this;
1✔
236
    }
237

238
    /**
239
     * {@inheritdoc}
240
     */
241
    public function setLogger(LoggerInterface $logger): void
242
    {
243
        $this->logger = $logger;
1✔
244
    }
245

246
    /**
247
     * Returns the logger instance.
248
     */
249
    public function getLogger(): LoggerInterface
250
    {
251
        return $this->logger;
1✔
252
    }
253

254
    /**
255
     * Returns debug mode state.
256
     */
257
    public function isDebug(): bool
258
    {
259
        return (bool) $this->debug;
1✔
260
    }
261

262
    /**
263
     * Returns build options.
264
     */
265
    public function getBuildOptions(): array
266
    {
267
        return $this->options;
1✔
268
    }
269

270
    /**
271
     * Set collected pages files.
272
     */
273
    public function setPagesFiles(Finder $content): void
274
    {
275
        $this->content = $content;
1✔
276
    }
277

278
    /**
279
     * Returns pages files.
280
     */
281
    public function getPagesFiles(): ?Finder
282
    {
283
        return $this->content;
1✔
284
    }
285

286
    /**
287
     * Set collected data.
288
     */
289
    public function setData(array $data): void
290
    {
291
        $this->data = $data;
1✔
292
    }
293

294
    /**
295
     * Returns data collection.
296
     */
297
    public function getData(?string $language = null): ?array
298
    {
299
        if ($language) {
1✔
300
            if (empty($this->data[$language])) {
1✔
301
                // fallback to default language
302
                return $this->data[$this->config->getLanguageDefault()];
1✔
303
            }
304

305
            return $this->data[$language];
1✔
306
        }
307

308
        return $this->data;
1✔
309
    }
310

311
    /**
312
     * Set collected static files.
313
     */
314
    public function setStatic(array $static): void
315
    {
316
        $this->static = $static;
1✔
317
    }
318

319
    /**
320
     * Returns static files collection.
321
     */
322
    public function getStatic(): array
323
    {
324
        return $this->static;
1✔
325
    }
326

327
    /**
328
     * Set/update Pages collection.
329
     */
330
    public function setPages(PagesCollection $pages): void
331
    {
332
        $this->pages = $pages;
1✔
333
    }
334

335
    /**
336
     * Returns pages collection.
337
     */
338
    public function getPages(): ?PagesCollection
339
    {
340
        return $this->pages;
1✔
341
    }
342

343
    /**
344
     * Set assets path collection.
345
     */
346
    public function setAssets(array $assets): void
347
    {
348
        $this->assets = $assets;
×
349
    }
350

351
    /**
352
     * Add an asset path to assets collection.
353
     */
354
    public function addAsset(string $path): void
355
    {
356
        if (!\in_array($path, $this->assets, true)) {
1✔
357
            $this->assets[] = $path;
1✔
358
        }
359
    }
360

361
    /**
362
     * Returns list of assets path.
363
     */
364
    public function getAssets(): ?array
365
    {
366
        return $this->assets;
1✔
367
    }
368

369
    /**
370
     * Set menus collection.
371
     */
372
    public function setMenus(array $menus): void
373
    {
374
        $this->menus = $menus;
1✔
375
    }
376

377
    /**
378
     * Returns all menus, for a language.
379
     */
380
    public function getMenus(string $language): Collection\Menu\Collection
381
    {
382
        return $this->menus[$language];
1✔
383
    }
384

385
    /**
386
     * Set taxonomies collection.
387
     */
388
    public function setTaxonomies(array $taxonomies): void
389
    {
390
        $this->taxonomies = $taxonomies;
1✔
391
    }
392

393
    /**
394
     * Returns taxonomies collection, for a language.
395
     */
396
    public function getTaxonomies(string $language): ?Collection\Taxonomy\Collection
397
    {
398
        return $this->taxonomies[$language];
1✔
399
    }
400

401
    /**
402
     * Set renderer object.
403
     */
404
    public function setRenderer(Renderer\RendererInterface $renderer): void
405
    {
406
        $this->renderer = $renderer;
1✔
407
    }
408

409
    /**
410
     * Returns Renderer object.
411
     */
412
    public function getRenderer(): Renderer\RendererInterface
413
    {
414
        return $this->renderer;
1✔
415
    }
416

417
    /**
418
     * Returns metrics array.
419
     */
420
    public function getMetrics(): array
421
    {
422
        return $this->metrics;
×
423
    }
424

425
    /**
426
     * Returns application version.
427
     *
428
     * @throws RuntimeException
429
     */
430
    public static function getVersion(): string
431
    {
432
        if (!isset(self::$version)) {
1✔
433
            try {
434
                $filePath = Util\File::getRealPath('VERSION');
1✔
435
                $version = Util\File::fileGetContents($filePath);
×
UNCOV
436
                if ($version === false) {
×
UNCOV
437
                    throw new RuntimeException(\sprintf('Can\'t read content of "%s".', $filePath));
×
438
                }
UNCOV
439
                self::$version = trim($version);
×
440
            } catch (\Exception) {
1✔
441
                self::$version = self::VERSION;
1✔
442
            }
443
        }
444

445
        return self::$version;
1✔
446
    }
447

448
    /**
449
     * Log configuration errors.
450
     */
451
    protected function logConfigError(): void
452
    {
453
        // warning about baseurl
454
        if (empty(trim((string) $this->config->get('baseurl'), '/'))) {
1✔
UNCOV
455
            $this->getLogger()->warning('`baseurl` configuration key is required in production.');
×
456
        }
457
    }
458
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc