Passed
Push — analysis-1bW4b3 ( c5dbea )
by Arnaud
05:20
created

Config::getPostProcessPath()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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