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

Cecilapp / Cecil / 6593079831

20 Oct 2023 09:59PM UTC coverage: 82.262% (-0.05%) from 82.308%
6593079831

Pull #1822

github

web-flow
Merge c0482243a into 37a2fde2e
Pull Request #1822: feat: path prefix for default language

14 of 14 new or added lines in 6 files covered. (100.0%)

2829 of 3439 relevant lines covered (82.26%)

0.82 hits per line

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

87.95
/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\Plateform;
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 = '7.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\Themes\Import',
41
        'Cecil\Step\Pages\Load',
42
        'Cecil\Step\Data\Load',
43
        'Cecil\Step\StaticFiles\Load',
44
        'Cecil\Step\Pages\Create',
45
        'Cecil\Step\Pages\Convert',
46
        'Cecil\Step\Taxonomies\Create',
47
        'Cecil\Step\Pages\Generate',
48
        'Cecil\Step\Menus\Create',
49
        'Cecil\Step\StaticFiles\Copy',
50
        'Cecil\Step\Pages\Render',
51
        'Cecil\Step\Pages\Save',
52
        'Cecil\Step\PostProcess\Html',
53
        'Cecil\Step\PostProcess\Css',
54
        'Cecil\Step\PostProcess\Js',
55
        'Cecil\Step\PostProcess\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 Menus collection. */
83
    protected $menus;
84

85
    /** @var array Taxonomies collection. */
86
    protected $taxonomies;
87

88
    /** @var Renderer\RendererInterface Renderer. */
89
    protected $renderer;
90

91
    /** @var GeneratorManager Generators manager. */
92
    protected $generatorManager;
93

94
    /** @var string Application version. */
95
    protected static $version;
96

97
    /**
98
     * @param Config|array|null    $config
99
     * @param LoggerInterface|null $logger
100
     */
101
    public function __construct($config = null, LoggerInterface $logger = null)
102
    {
103
        // set logger
104
        if ($logger === null) {
1✔
105
            $logger = new PrintLogger(self::VERBOSITY_VERBOSE);
×
106
        }
107
        $this->setLogger($logger);
1✔
108
        // set config
109
        $this->setConfig($config)->setSourceDir(null)->setDestinationDir(null);
1✔
110
        // debug mode?
111
        if (getenv('CECIL_DEBUG') == 'true' || (bool) $this->getConfig()->get('debug')) {
1✔
112
            $this->debug = true;
1✔
113
        }
114
    }
115

116
    /**
117
     * Creates a new Builder instance.
118
     */
119
    public static function create(): self
120
    {
121
        $class = new \ReflectionClass(\get_called_class());
1✔
122

123
        return $class->newInstanceArgs(\func_get_args());
1✔
124
    }
125

126
    /**
127
     * Builds a new website.
128
     */
129
    public function build(array $options): self
130
    {
131
        // set start script time and memory usage
132
        $startTime = microtime(true);
1✔
133
        $startMemory = memory_get_usage();
1✔
134

135
        // checks the configuration
136
        $this->validConfig();
1✔
137

138
        // prepare options
139
        $this->options = array_merge([
1✔
140
            'drafts'  => false, // build drafts or not
1✔
141
            'dry-run' => false, // if dry-run is true, generated files are not saved
1✔
142
            'page'    => '',    // specific page to build
1✔
143
        ], $options);
1✔
144

145
        // process each step
146
        $steps = [];
1✔
147
        // init...
148
        foreach ($this->steps as $step) {
1✔
149
            /** @var Step\StepInterface $stepObject */
150
            $stepObject = new $step($this);
1✔
151
            $stepObject->init($this->options);
1✔
152
            if ($stepObject->canProcess()) {
1✔
153
                $steps[] = $stepObject;
1✔
154
            }
155
        }
156
        // ...and process!
157
        $stepNumber = 0;
1✔
158
        $stepsTotal = \count($steps);
1✔
159
        foreach ($steps as $step) {
1✔
160
            $stepNumber++;
1✔
161
            /** @var Step\StepInterface $step */
162
            $this->getLogger()->notice($step->getName(), ['step' => [$stepNumber, $stepsTotal]]);
1✔
163
            $stepStartTime = microtime(true);
1✔
164
            $stepStartMemory = memory_get_usage();
1✔
165
            $step->process();
1✔
166
            $this->getLogger()->info(sprintf('%s done in %s (%s)', $step->getName(), Util::convertMicrotime((float) $stepStartTime), Util::convertMemory(memory_get_usage() - $stepStartMemory)));
1✔
167
        }
168

169
        // process duration
170
        $this->getLogger()->notice(sprintf('Built in %s (%s)', Util::convertMicrotime($startTime), Util::convertMemory(memory_get_usage() - $startMemory)));
1✔
171

172
        return $this;
1✔
173
    }
174

175
    /**
176
     * Set configuration.
177
     *
178
     * @param Config|array|null $config
179
     */
180
    public function setConfig($config): self
181
    {
182
        if (!$config instanceof Config) {
1✔
183
            $config = new Config($config);
1✔
184
        }
185
        if ($this->config !== $config) {
1✔
186
            $this->config = $config;
1✔
187
        }
188

189
        return $this;
1✔
190
    }
191

192
    /**
193
     * Returns configuration.
194
     */
195
    public function getConfig(): Config
196
    {
197
        return $this->config;
1✔
198
    }
199

200
    /**
201
     * Config::setSourceDir() alias.
202
     */
203
    public function setSourceDir(string $sourceDir = null): self
204
    {
205
        $this->config->setSourceDir($sourceDir);
1✔
206

207
        return $this;
1✔
208
    }
209

210
    /**
211
     * Config::setDestinationDir() alias.
212
     */
213
    public function setDestinationDir(string $destinationDir = null): self
214
    {
215
        $this->config->setDestinationDir($destinationDir);
1✔
216

217
        return $this;
1✔
218
    }
219

220
    /**
221
     * {@inheritdoc}
222
     */
223
    public function setLogger(LoggerInterface $logger)
224
    {
225
        $this->logger = $logger;
1✔
226
    }
227

228
    /**
229
     * Returns the logger instance.
230
     */
231
    public function getLogger(): LoggerInterface
232
    {
233
        return $this->logger;
1✔
234
    }
235

236
    /**
237
     * Returns debug mode state.
238
     */
239
    public function isDebug(): bool
240
    {
241
        return $this->debug;
1✔
242
    }
243

244
    /**
245
     * Returns build options.
246
     */
247
    public function getBuildOptions(): array
248
    {
249
        return $this->options;
1✔
250
    }
251

252
    /**
253
     * Set collected pages files.
254
     */
255
    public function setPagesFiles(Finder $content): void
256
    {
257
        $this->content = $content;
1✔
258
    }
259

260
    /**
261
     * Returns pages files.
262
     */
263
    public function getPagesFiles(): ?Finder
264
    {
265
        return $this->content;
1✔
266
    }
267

268
    /**
269
     * Set collected data.
270
     */
271
    public function setData(array $data): void
272
    {
273
        $this->data = $data;
1✔
274
    }
275

276
    /**
277
     * Returns data collection.
278
     */
279
    public function getData(): array
280
    {
281
        return $this->data;
1✔
282
    }
283

284
    /**
285
     * Set collected static files.
286
     */
287
    public function setStatic(array $static): void
288
    {
289
        $this->static = $static;
1✔
290
    }
291

292
    /**
293
     * Returns static files collection.
294
     */
295
    public function getStatic(): array
296
    {
297
        return $this->static;
1✔
298
    }
299

300
    /**
301
     * Set/update Pages collection.
302
     */
303
    public function setPages(PagesCollection $pages): void
304
    {
305
        $this->pages = $pages;
1✔
306
    }
307

308
    /**
309
     * Returns pages collection.
310
     */
311
    public function getPages(): ?PagesCollection
312
    {
313
        return $this->pages;
1✔
314
    }
315

316
    /**
317
     * Set menus collection.
318
     */
319
    public function setMenus(array $menus): void
320
    {
321
        $this->menus = $menus;
1✔
322
    }
323

324
    /**
325
     * Returns all menus, for a language.
326
     */
327
    public function getMenus(string $language): Collection\Menu\Collection
328
    {
329
        return $this->menus[$language];
1✔
330
    }
331

332
    /**
333
     * Set taxonomies collection.
334
     */
335
    public function setTaxonomies(array $taxonomies): void
336
    {
337
        $this->taxonomies = $taxonomies;
1✔
338
    }
339

340
    /**
341
     * Returns taxonomies collection, for a language.
342
     */
343
    public function getTaxonomies(string $language): ?Collection\Taxonomy\Collection
344
    {
345
        return $this->taxonomies[$language];
1✔
346
    }
347

348
    /**
349
     * Set renderer object.
350
     */
351
    public function setRenderer(Renderer\RendererInterface $renderer): void
352
    {
353
        $this->renderer = $renderer;
1✔
354
    }
355

356
    /**
357
     * Returns Renderer object.
358
     */
359
    public function getRenderer(): Renderer\RendererInterface
360
    {
361
        return $this->renderer;
1✔
362
    }
363

364
    /**
365
     * Returns application version.
366
     *
367
     * @throws RuntimeException
368
     */
369
    public static function getVersion(): string
370
    {
371
        if (!isset(self::$version)) {
1✔
372
            $filePath = __DIR__ . '/../VERSION';
1✔
373
            if (Plateform::isPhar()) {
1✔
374
                $filePath = Plateform::getPharPath() . '/VERSION';
×
375
            }
376

377
            try {
378
                if (!file_exists($filePath)) {
1✔
379
                    throw new RuntimeException(sprintf('%s file doesn\'t exist!', $filePath));
1✔
380
                }
381
                $version = Util\File::fileGetContents($filePath);
×
382
                if ($version === false) {
×
383
                    throw new RuntimeException(sprintf('Can\'t get %s file!', $filePath));
×
384
                }
385
                self::$version = trim($version);
×
386
            } catch (\Exception $e) {
1✔
387
                self::$version = self::VERSION;
1✔
388
            }
389
        }
390

391
        return self::$version;
1✔
392
    }
393

394
    /**
395
     * Checks the configuration.
396
     */
397
    protected function validConfig(): void
398
    {
399
        // baseurl
400
        if (empty(trim((string) $this->config->get('baseurl'), '/'))) {
1✔
401
            $this->getLogger()->error('Config: `baseurl` is required in production (e.g.: "baseurl: https://example.com/").');
×
402
        }
403
        // default language
404
        if (!preg_match('/^' . Config::LANG_CODE_PATTERN . '$/', $this->config->getLanguageDefault())) {
1✔
405
            throw new RuntimeException(sprintf('Config: default language code "%s" is not valid (e.g.: "language: fr-FR").', $this->config->getLanguageDefault()));
×
406
        }
407
        // locales
408
        foreach ($this->config->getLanguages() as $lang) {
1✔
409
            if (!isset($lang['locale'])) {
1✔
410
                throw new RuntimeException('Config: a language locale is not defined.');
×
411
            }
412
            if (!preg_match('/^' . Config::LANG_LOCALE_PATTERN . '$/', $lang['locale'])) {
1✔
413
                throw new RuntimeException(sprintf('Config: the language locale "%s" is not valid (e.g.: "locale: fr_FR").', $lang['locale']));
×
414
            }
415
        }
416
    }
417
}
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

© 2026 Coveralls, Inc