Completed
Push — languages ( dc8bf0...32d752 )
by Arnaud
01:58
created

Config::getLanguageIndex()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

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