Passed
Push — dependabot/composer/voku/html-... ( 60135f...807e35 )
by
unknown
04:25 queued 01:14
created

Config::importSiteConfig()   A

Complexity

Conditions 4
Paths 1

Size

Total Lines 27
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 16
nc 1
nop 0
dl 0
loc 27
rs 9.7333
c 0
b 0
f 0
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
namespace Cecil;
12
13
use Cecil\Exception\Exception;
14
use Cecil\Util\Plateform;
15
use Dflydev\DotAccessData\Data;
16
17
/**
18
 * Class Config.
19
 */
20
class Config
21
{
22
    /** @var Data Configuration is a Data object. */
23
    protected $data;
24
    /** @var array Configuration. */
25
    protected $siteConfig;
26
    /** @var string Source directory. */
27
    protected $sourceDir;
28
    /** @var string Destination directory. */
29
    protected $destinationDir;
30
31
    /**
32
     * @param array|null $config
33
     */
34
    public function __construct(array $config = null)
35
    {
36
        // load default configuration
37
        $defaultConfig = realpath(Util::joinFile(__DIR__, '..', 'config/default.php'));
38
        if (Plateform::isPhar()) {
39
            $defaultConfig = Util::joinPath(Plateform::getPharPath(), 'config/default.php');
40
        }
41
        $this->data = new Data(include $defaultConfig);
42
43
        // import site config
44
        $this->siteConfig = $config;
45
        $this->importSiteConfig();
46
    }
47
48
    /**
49
     * Import site configuration.
50
     *
51
     * @return void
52
     */
53
    protected function importSiteConfig(): void
54
    {
55
        $this->data->import($this->siteConfig);
56
57
        /**
58
         * Overrides configuration with environment variables.
59
         */
60
        $data = $this->getData();
61
        $applyEnv = function ($array) use ($data) {
62
            $iterator = new \RecursiveIteratorIterator(
63
                new \RecursiveArrayIterator($array),
64
                \RecursiveIteratorIterator::SELF_FIRST
65
            );
66
            $iterator->rewind();
67
            while ($iterator->valid()) {
68
                $path = [];
69
                foreach (range(0, $iterator->getDepth()) as $depth) {
70
                    $path[] = $iterator->getSubIterator($depth)->key();
71
                }
72
                $sPath = implode('_', $path);
73
                if ($getEnv = getenv('CECIL_'.strtoupper($sPath))) {
74
                    $data->set(str_replace('_', '.', strtolower($sPath)), $getEnv);
75
                }
76
                $iterator->next();
77
            }
78
        };
79
        $applyEnv($data->export());
80
    }
81
82
    /**
83
     * Import (theme) configuration.
84
     *
85
     * @param array|null $config
86
     *
87
     * @return void
88
     */
89
    public function import(array $config): void
90
    {
91
        $this->data->import($config);
92
93
        // re-import site config
94
        $this->importSiteConfig();
95
    }
96
97
    /**
98
     * Set a Data object as configuration.
99
     *
100
     * @param Data $data
101
     *
102
     * @return self
103
     */
104
    protected function setData(Data $data): self
105
    {
106
        if ($this->data !== $data) {
107
            $this->data = $data;
108
        }
109
110
        return $this;
111
    }
112
113
    /**
114
     * Get configuration as a Data object.
115
     *
116
     * @return Data
117
     */
118
    public function getData(): Data
119
    {
120
        return $this->data;
121
    }
122
123
    /**
124
     * Get configuration as an array.
125
     *
126
     * @return array
127
     */
128
    public function getAsArray(): array
129
    {
130
        return $this->data->export();
131
    }
132
133
    /**
134
     * Is configuration's key' exists?
135
     *
136
     * @param string $key
137
     *
138
     * @return bool
139
     */
140
    public function has(string $key): bool
141
    {
142
        return $this->data->has($key);
143
    }
144
145
    /**
146
     * Get the value of a configuration's key'.
147
     *
148
     * @param string      $key
149
     * @param string|null $language
150
     *
151
     * @return mixed|null
152
     */
153
    public function get(string $key, string $language = null)
154
    {
155
        if ($language !== null) {
156
            $index = $this->getLanguageIndex($language);
157
            $keyLang = sprintf('languages.%s.config.%s', $index, $key);
158
            if ($this->data->has($keyLang)) {
159
                return $this->data->get($keyLang);
160
            }
161
        }
162
163
        return $this->data->get($key);
164
    }
165
166
    /**
167
     * Set the source directory.
168
     *
169
     * @param string|null $sourceDir
170
     *
171
     * @throws \InvalidArgumentException
172
     *
173
     * @return self
174
     */
175
    public function setSourceDir(string $sourceDir = null): self
176
    {
177
        if ($sourceDir === null) {
178
            $sourceDir = getcwd();
179
        }
180
        if (!is_dir($sourceDir)) {
181
            throw new \InvalidArgumentException(sprintf('The directory "%s" is not a valid source!', $sourceDir));
182
        }
183
        $this->sourceDir = $sourceDir;
184
185
        return $this;
186
    }
187
188
    /**
189
     * Get the source directory.
190
     *
191
     * @return string
192
     */
193
    public function getSourceDir(): string
194
    {
195
        return $this->sourceDir;
196
    }
197
198
    /**
199
     * Set the destination directory.
200
     *
201
     * @param string|null $destinationDir
202
     *
203
     * @throws \InvalidArgumentException
204
     *
205
     * @return self
206
     */
207
    public function setDestinationDir(string $destinationDir = null): self
208
    {
209
        if ($destinationDir === null) {
210
            $destinationDir = $this->sourceDir;
211
        }
212
        if (!is_dir($destinationDir)) {
213
            throw new \InvalidArgumentException(sprintf(
214
                'The directory "%s" is not a valid destination!',
215
                $destinationDir
216
            ));
217
        }
218
        $this->destinationDir = $destinationDir;
219
220
        return $this;
221
    }
222
223
    /**
224
     * Get the destination directory.
225
     *
226
     * @return string
227
     */
228
    public function getDestinationDir(): string
229
    {
230
        return $this->destinationDir;
231
    }
232
233
    /**
234
     * Path helpers.
235
     */
236
237
    /**
238
     * Return the path of the content directory.
239
     *
240
     * @return string
241
     */
242
    public function getContentPath(): string
243
    {
244
        return Util::joinFile($this->getSourceDir(), (string) $this->get('content.dir'));
245
    }
246
247
    /**
248
     * Return the path of the data directory.
249
     *
250
     * @return string
251
     */
252
    public function getDataPath(): string
253
    {
254
        return Util::joinFile($this->getSourceDir(), (string) $this->get('data.dir'));
255
    }
256
257
    /**
258
     * Return the path of templates directory.
259
     *
260
     * @return string
261
     */
262
    public function getLayoutsPath(): string
263
    {
264
        return Util::joinFile($this->getSourceDir(), (string) $this->get('layouts.dir'));
265
    }
266
267
    /**
268
     * Return the path of themes directory.
269
     *
270
     * @return string
271
     */
272
    public function getThemesPath(): string
273
    {
274
        return Util::joinFile($this->getSourceDir(), (string) $this->get('themes.dir'));
275
    }
276
277
    /**
278
     * Return the path of internal templates directory.
279
     *
280
     * @return string
281
     */
282
    public function getInternalLayoutsPath(): string
283
    {
284
        return Util::joinPath(__DIR__, '..', (string) $this->get('layouts.internal.dir'));
285
    }
286
287
    /**
288
     * Return the path of the output directory.
289
     *
290
     * @return string
291
     */
292
    public function getOutputPath(): string
293
    {
294
        return Util::joinFile($this->getDestinationDir(), (string) $this->get('output.dir'));
295
    }
296
297
    /**
298
     * Return the path of static files directory.
299
     *
300
     * @return string
301
     */
302
    public function getStaticPath(): string
303
    {
304
        return Util::joinFile($this->getSourceDir(), (string) $this->get('static.dir'));
305
    }
306
307
    /**
308
     * Is cache dir is absolute to system files
309
     * or relative to project destination?
310
     *
311
     * @return bool
312
     */
313
    public function isCacheDirIsAbsolute(): bool
314
    {
315
        $path = (string) $this->get('cache.dir');
316
        if (Util::joinFile($path) == realpath(Util::joinFile($path))) {
317
            return true;
318
        }
319
320
        return false;
321
    }
322
323
    /**
324
     * Return cache path.
325
     *
326
     * @return string
327
     */
328
    public function getCachePath(): string
329
    {
330
        if ($this->isCacheDirIsAbsolute()) {
331
            $cacheDir = Util::joinFile((string) $this->get('cache.dir'));
332
            $cacheDir = Util::joinFile($cacheDir, 'cecil');
333
            Util::getFS()->mkdir($cacheDir);
334
335
            return $cacheDir;
336
        }
337
338
        return Util::joinFile($this->getDestinationDir(), (string) $this->get('cache.dir'));
339
    }
340
341
    /**
342
     * Return the property value of an output format.
343
     *
344
     * @param string $name
345
     * @param string $property
346
     *
347
     * @return string|array|null
348
     */
349
    public function getOutputFormatProperty(string $name, string $property)
350
    {
351
        $properties = array_column((array) $this->get('output.formats'), $property, 'name');
352
353
        if (empty($properties)) {
354
            throw new Exception(sprintf(
355
                'Property "%s" is not defined for format "%s".',
356
                $property,
357
                $name
358
            ));
359
        }
360
361
        if (!array_key_exists($name, $properties)) {
362
            return null;
363
        }
364
365
        return $properties[$name];
366
    }
367
368
    /**
369
     * Theme helpers.
370
     */
371
372
    /**
373
     * Return theme(s) as an array.
374
     *
375
     * @return array|null
376
     */
377
    public function getTheme(): ?array
378
    {
379
        if ($themes = $this->get('theme')) {
380
            if (is_array($themes)) {
381
                return $themes;
382
            }
383
384
            return [$themes];
385
        }
386
387
        return null;
388
    }
389
390
    /**
391
     * Has a (valid) theme(s)?
392
     *
393
     * @throws Exception
394
     *
395
     * @return bool
396
     */
397
    public function hasTheme(): bool
398
    {
399
        if ($themes = $this->getTheme()) {
400
            foreach ($themes as $theme) {
401
                if (!Util::getFS()->exists($this->getThemeDirPath($theme, 'layouts'))) {
402
                    throw new Exception(sprintf(
403
                        'Theme directory "%s/%s/layouts" not found!',
404
                        $this->getThemesPath(),
405
                        $theme
406
                    ));
407
                }
408
            }
409
410
            return true;
411
        }
412
413
        return false;
414
    }
415
416
    /**
417
     * Return the path of a specific theme's directory.
418
     * ("layouts" by default).
419
     *
420
     * @param string $theme
421
     * @param string $dir
422
     *
423
     * @return string
424
     */
425
    public function getThemeDirPath(string $theme, string $dir = 'layouts'): string
426
    {
427
        return Util::joinFile($this->getThemesPath(), $theme, $dir);
428
    }
429
430
    /**
431
     * Language helpers.
432
     */
433
434
    /**
435
     * Return an array of available languages.
436
     *
437
     * @return array
438
     */
439
    public function getLanguages(): array
440
    {
441
        return $this->get('languages');
442
    }
443
444
    /**
445
     * Return the default language code (ie: "en", "fr-fr", etc.).
446
     *
447
     * @return string
448
     */
449
    public function getLanguageDefault(): string
450
    {
451
        if (!$this->get('language')) {
452
            throw new Exception('There is no default "language" in configuration.');
453
        }
454
455
        return $this->get('language');
456
    }
457
458
    /**
459
     * Return a language code index.
460
     *
461
     * @param string $code
462
     *
463
     * @return int
464
     */
465
    public function getLanguageIndex(string $code): int
466
    {
467
        $array = array_column($this->getLanguages(), 'code');
468
469
        if (!$index = array_search($code, $array)) {
470
            throw new Exception(sprintf('The language code "%s" is not defined.', $code));
471
        }
472
473
        return $index;
474
    }
475
476
    /**
477
     * Return the property value of a (specified or default) language.
478
     *
479
     * @param string      $property
480
     * @param string|null $code
481
     *
482
     * @return string|null
483
     */
484
    public function getLanguageProperty(string $property, string $code = null): ?string
485
    {
486
        $code = $code ?? $this->getLanguageDefault();
487
488
        $properties = array_column($this->getLanguages(), $property, 'code');
489
490
        if (empty($properties)) {
491
            throw new Exception(sprintf(
492
                'Property "%s" is not defined for language "%s".',
493
                $property,
494
                $code
495
            ));
496
        }
497
498
        return $properties[$code];
499
    }
500
}
501