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
|
|
|
//DEBUG |
160
|
|
|
die('POUET'); |
161
|
|
|
$keyLang = "languages.$language.$key"; |
|
|
|
|
162
|
|
|
if ($this->data->has($keyLang)) { |
163
|
|
|
return $this->data->get($keyLang); |
164
|
|
|
} |
165
|
|
|
} |
166
|
|
|
|
167
|
|
|
return $this->data->get($key); |
168
|
|
|
} |
169
|
|
|
|
170
|
|
|
/** |
171
|
|
|
* Set the source directory. |
172
|
|
|
* |
173
|
|
|
* @param string|null $sourceDir |
174
|
|
|
* |
175
|
|
|
* @throws \InvalidArgumentException |
176
|
|
|
* |
177
|
|
|
* @return $this |
178
|
|
|
*/ |
179
|
|
|
public function setSourceDir(string $sourceDir = null): self |
180
|
|
|
{ |
181
|
|
|
if ($sourceDir === null) { |
182
|
|
|
$sourceDir = getcwd(); |
183
|
|
|
} |
184
|
|
|
if (!is_dir($sourceDir)) { |
185
|
|
|
throw new \InvalidArgumentException(sprintf('The directory "%s" is not a valid source!', $sourceDir)); |
186
|
|
|
} |
187
|
|
|
$this->sourceDir = $sourceDir; |
188
|
|
|
|
189
|
|
|
return $this; |
190
|
|
|
} |
191
|
|
|
|
192
|
|
|
/** |
193
|
|
|
* Get the source directory. |
194
|
|
|
* |
195
|
|
|
* @return string |
196
|
|
|
*/ |
197
|
|
|
public function getSourceDir(): string |
198
|
|
|
{ |
199
|
|
|
return $this->sourceDir; |
200
|
|
|
} |
201
|
|
|
|
202
|
|
|
/** |
203
|
|
|
* Set the destination directory. |
204
|
|
|
* |
205
|
|
|
* @param string|null $destinationDir |
206
|
|
|
* |
207
|
|
|
* @throws \InvalidArgumentException |
208
|
|
|
* |
209
|
|
|
* @return $this |
210
|
|
|
*/ |
211
|
|
|
public function setDestinationDir(string $destinationDir = null): self |
212
|
|
|
{ |
213
|
|
|
if ($destinationDir === null) { |
214
|
|
|
$destinationDir = $this->sourceDir; |
215
|
|
|
} |
216
|
|
|
if (!is_dir($destinationDir)) { |
217
|
|
|
throw new \InvalidArgumentException(sprintf( |
218
|
|
|
'The directory "%s" is not a valid destination!', |
219
|
|
|
$destinationDir |
220
|
|
|
)); |
221
|
|
|
} |
222
|
|
|
$this->destinationDir = $destinationDir; |
223
|
|
|
|
224
|
|
|
return $this; |
225
|
|
|
} |
226
|
|
|
|
227
|
|
|
/** |
228
|
|
|
* Get the destination directory. |
229
|
|
|
* |
230
|
|
|
* @return string |
231
|
|
|
*/ |
232
|
|
|
public function getDestinationDir(): string |
233
|
|
|
{ |
234
|
|
|
return $this->destinationDir; |
235
|
|
|
} |
236
|
|
|
|
237
|
|
|
/** |
238
|
|
|
* Paths helpers. |
239
|
|
|
*/ |
240
|
|
|
|
241
|
|
|
/** |
242
|
|
|
* Return the path of the content directory. |
243
|
|
|
* |
244
|
|
|
* @return string |
245
|
|
|
*/ |
246
|
|
|
public function getContentPath(): string |
247
|
|
|
{ |
248
|
|
|
return $this->getSourceDir().'/'.$this->get('content.dir'); |
249
|
|
|
} |
250
|
|
|
|
251
|
|
|
/** |
252
|
|
|
* Return the path of the data directory. |
253
|
|
|
* |
254
|
|
|
* @return string |
255
|
|
|
*/ |
256
|
|
|
public function getDataPath(): string |
257
|
|
|
{ |
258
|
|
|
return $this->getSourceDir().'/'.$this->get('data.dir'); |
259
|
|
|
} |
260
|
|
|
|
261
|
|
|
/** |
262
|
|
|
* Return the path of templates directory. |
263
|
|
|
* |
264
|
|
|
* @return string |
265
|
|
|
*/ |
266
|
|
|
public function getLayoutsPath(): string |
267
|
|
|
{ |
268
|
|
|
return $this->getSourceDir().'/'.$this->get('layouts.dir'); |
269
|
|
|
} |
270
|
|
|
|
271
|
|
|
/** |
272
|
|
|
* Return the path of themes directory. |
273
|
|
|
* |
274
|
|
|
* @return string |
275
|
|
|
*/ |
276
|
|
|
public function getThemesPath(): string |
277
|
|
|
{ |
278
|
|
|
return $this->getSourceDir().'/'.$this->get('themes.dir'); |
279
|
|
|
} |
280
|
|
|
|
281
|
|
|
/** |
282
|
|
|
* Return the path of internal templates directory. |
283
|
|
|
* |
284
|
|
|
* @return string |
285
|
|
|
*/ |
286
|
|
|
public function getInternalLayoutsPath(): string |
287
|
|
|
{ |
288
|
|
|
return __DIR__.'/../'.$this->get('layouts.internal.dir'); |
289
|
|
|
} |
290
|
|
|
|
291
|
|
|
/** |
292
|
|
|
* Return the path of the output directory. |
293
|
|
|
* |
294
|
|
|
* @return string |
295
|
|
|
*/ |
296
|
|
|
public function getOutputPath(): string |
297
|
|
|
{ |
298
|
|
|
return $this->getDestinationDir().'/'.$this->get('output.dir'); |
299
|
|
|
} |
300
|
|
|
|
301
|
|
|
/** |
302
|
|
|
* Return the path of static files directory. |
303
|
|
|
* |
304
|
|
|
* @return string |
305
|
|
|
*/ |
306
|
|
|
public function getStaticPath(): string |
307
|
|
|
{ |
308
|
|
|
return $this->getSourceDir().'/'.$this->get('static.dir'); |
309
|
|
|
} |
310
|
|
|
|
311
|
|
|
/** |
312
|
|
|
* Return a "clean" array of an output format. |
313
|
|
|
* |
314
|
|
|
* @param string $format |
315
|
|
|
* |
316
|
|
|
* @return array |
317
|
|
|
*/ |
318
|
|
|
public function getOutputFormat(string $format): array |
319
|
|
|
{ |
320
|
|
|
$default = [ |
321
|
|
|
'mediatype' => null, // 'text/html' |
322
|
|
|
'subpath' => null, // '' |
323
|
|
|
'suffix' => null, // '/index' |
324
|
|
|
'extension' => null, // 'html' |
325
|
|
|
]; |
326
|
|
|
|
327
|
|
|
$result = $this->get(sprintf('output.formats.%s', $format)); |
328
|
|
|
|
329
|
|
|
return array_merge($default, $result); |
330
|
|
|
} |
331
|
|
|
|
332
|
|
|
/** |
333
|
|
|
* Theme helpers. |
334
|
|
|
*/ |
335
|
|
|
|
336
|
|
|
/** |
337
|
|
|
* Return theme(s) as an array. |
338
|
|
|
* |
339
|
|
|
* @return array|null |
340
|
|
|
*/ |
341
|
|
|
public function getTheme(): ?array |
342
|
|
|
{ |
343
|
|
|
if ($themes = $this->get('theme')) { |
344
|
|
|
if (is_array($themes)) { |
345
|
|
|
return $themes; |
346
|
|
|
} |
347
|
|
|
|
348
|
|
|
return [$themes]; |
349
|
|
|
} |
350
|
|
|
|
351
|
|
|
return null; |
352
|
|
|
} |
353
|
|
|
|
354
|
|
|
/** |
355
|
|
|
* Has a (valid) theme(s)? |
356
|
|
|
* |
357
|
|
|
* @throws Exception |
358
|
|
|
* |
359
|
|
|
* @return bool |
360
|
|
|
*/ |
361
|
|
|
public function hasTheme(): bool |
362
|
|
|
{ |
363
|
|
|
if ($themes = $this->getTheme()) { |
364
|
|
|
foreach ($themes as $theme) { |
365
|
|
|
if (!Util::getFS()->exists($this->getThemeDirPath($theme, 'layouts'))) { |
366
|
|
|
throw new Exception(sprintf( |
367
|
|
|
"Theme directory '%s/%s/layouts' not found!", |
368
|
|
|
$this->getThemesPath(), |
369
|
|
|
$theme |
370
|
|
|
)); |
371
|
|
|
} |
372
|
|
|
} |
373
|
|
|
|
374
|
|
|
return true; |
375
|
|
|
} |
376
|
|
|
|
377
|
|
|
return false; |
378
|
|
|
} |
379
|
|
|
|
380
|
|
|
/** |
381
|
|
|
* Return the path of a specific theme's directory. |
382
|
|
|
* ("layouts" by default). |
383
|
|
|
* |
384
|
|
|
* @param string $theme |
385
|
|
|
* @param string $dir |
386
|
|
|
* |
387
|
|
|
* @return string |
388
|
|
|
*/ |
389
|
|
|
public function getThemeDirPath(string $theme, string $dir = 'layouts'): string |
390
|
|
|
{ |
391
|
|
|
return $this->getThemesPath().'/'.$theme.'/'.$dir; |
392
|
|
|
} |
393
|
|
|
|
394
|
|
|
/** |
395
|
|
|
* Language helpers. |
396
|
|
|
*/ |
397
|
|
|
|
398
|
|
|
/** |
399
|
|
|
* Return an array of available languages. |
400
|
|
|
* |
401
|
|
|
* @return array |
402
|
|
|
*/ |
403
|
|
|
public function getLanguages(): array |
404
|
|
|
{ |
405
|
|
|
return $this->get('languages'); |
406
|
|
|
} |
407
|
|
|
|
408
|
|
|
/** |
409
|
|
|
* Return the default language code (ie: "en", "fr-fr", etc.). |
410
|
|
|
* |
411
|
|
|
* @return string |
412
|
|
|
*/ |
413
|
|
|
public function getLanguageDefault(): string |
414
|
|
|
{ |
415
|
|
|
if ($this->get('language')) { |
416
|
|
|
return $this->get('language'); |
417
|
|
|
} |
418
|
|
|
|
419
|
|
|
$languages = $this->getLanguages(); |
420
|
|
|
if (!is_array($languages)) { |
421
|
|
|
throw new Exception('There is no default "language" in configuration!'); |
422
|
|
|
} |
423
|
|
|
reset($languages); |
424
|
|
|
|
425
|
|
|
return $languages['code']; |
426
|
|
|
} |
427
|
|
|
|
428
|
|
|
/** |
429
|
|
|
* Return the property value of a (specified or default) language. |
430
|
|
|
* |
431
|
|
|
* @param string $property |
432
|
|
|
* @param string|null $key |
433
|
|
|
* |
434
|
|
|
* @return string |
435
|
|
|
*/ |
436
|
|
|
public function getLanguageProperty($property, $key = null): string |
437
|
|
|
{ |
438
|
|
|
$properties = ['name', 'locale']; |
439
|
|
|
$languageProperties = $this->getLanguageProperties($key); |
|
|
|
|
440
|
|
|
|
441
|
|
|
if (!in_array($property, $properties)) { |
442
|
|
|
throw new Exception(sprintf( |
443
|
|
|
'Property language "%s" is not available!', |
444
|
|
|
$property |
445
|
|
|
)); |
446
|
|
|
} |
447
|
|
|
if (!\array_key_exists($property, $languageProperties)) { |
448
|
|
|
throw new Exception(sprintf( |
449
|
|
|
'Property "%s" is not defined for language "%s"!', |
450
|
|
|
$property, |
451
|
|
|
$languageProperties['name'] |
452
|
|
|
)); |
453
|
|
|
} |
454
|
|
|
|
455
|
|
|
return $languageProperties[$property]; |
456
|
|
|
} |
457
|
|
|
} |
458
|
|
|
|
This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.
Unreachable code is most often the result of
return
,die
orexit
statements that have been added for debug purposes.In the above example, the last
return false
will never be executed, because a return statement has already been met in every possible execution path.