1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Phinx |
4
|
|
|
* |
5
|
|
|
* (The MIT license) |
6
|
|
|
* Copyright (c) 2015 Rob Morgan |
7
|
|
|
* |
8
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy |
9
|
|
|
* of this software and associated * documentation files (the "Software"), to |
10
|
|
|
* deal in the Software without restriction, including without limitation the |
11
|
|
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or |
12
|
|
|
* sell copies of the Software, and to permit persons to whom the Software is |
13
|
|
|
* furnished to do so, subject to the following conditions: |
14
|
|
|
* |
15
|
|
|
* The above copyright notice and this permission notice shall be included in |
16
|
|
|
* all copies or substantial portions of the Software. |
17
|
|
|
* |
18
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
19
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
20
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
21
|
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
22
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
23
|
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
24
|
|
|
* IN THE SOFTWARE. |
25
|
|
|
* |
26
|
|
|
* @package Phinx |
27
|
|
|
* @subpackage Phinx\Config |
28
|
|
|
*/ |
29
|
|
|
namespace Phinx\Config; |
30
|
|
|
|
31
|
|
|
use Symfony\Component\Yaml\Yaml; |
32
|
|
|
|
33
|
|
|
/** |
34
|
|
|
* Phinx configuration class. |
35
|
|
|
* |
36
|
|
|
* @package Phinx |
37
|
|
|
* @author Rob Morgan |
38
|
|
|
*/ |
39
|
|
|
class Config implements ConfigInterface, NamespaceAwareInterface |
40
|
|
|
{ |
41
|
|
|
use NamespaceAwareTrait; |
42
|
|
|
|
43
|
|
|
/** |
44
|
|
|
* The value that identifies a version order by creation time. |
45
|
|
|
*/ |
46
|
|
|
const VERSION_ORDER_CREATION_TIME = 'creation'; |
47
|
|
|
|
48
|
|
|
/** |
49
|
|
|
* The value that identifies a version order by execution time. |
50
|
|
|
*/ |
51
|
|
|
const VERSION_ORDER_EXECUTION_TIME = 'execution'; |
52
|
|
|
|
53
|
|
|
/** |
54
|
|
|
* @var array |
55
|
|
|
*/ |
56
|
|
|
private $values = []; |
57
|
|
|
|
58
|
|
|
/** |
59
|
|
|
* @var string |
60
|
|
|
*/ |
61
|
|
|
protected $configFilePath; |
62
|
|
|
|
63
|
|
|
/** |
64
|
|
|
* {@inheritdoc} |
65
|
|
|
*/ |
66
|
448 |
|
public function __construct(array $configArray, $configFilePath = null) |
67
|
|
|
{ |
68
|
448 |
|
$this->configFilePath = $configFilePath; |
69
|
448 |
|
$this->values = $this->replaceTokens($configArray); |
70
|
448 |
|
} |
71
|
|
|
|
72
|
|
|
/** |
73
|
|
|
* Create a new instance of the config class using a Yaml file path. |
74
|
|
|
* |
75
|
|
|
* @param string $configFilePath Path to the Yaml File |
76
|
|
|
* @throws \RuntimeException |
77
|
|
|
* @return \Phinx\Config\Config |
78
|
|
|
*/ |
79
|
2 |
View Code Duplication |
public static function fromYaml($configFilePath) |
|
|
|
|
80
|
|
|
{ |
81
|
2 |
|
$configFile = file_get_contents($configFilePath); |
82
|
2 |
|
$configArray = Yaml::parse($configFile); |
83
|
|
|
|
84
|
2 |
|
if (!is_array($configArray)) { |
85
|
1 |
|
throw new \RuntimeException(sprintf( |
86
|
1 |
|
'File \'%s\' must be valid YAML', |
87
|
|
|
$configFilePath |
88
|
1 |
|
)); |
89
|
|
|
} |
90
|
1 |
|
|
91
|
|
|
return new static($configArray, $configFilePath); |
92
|
|
|
} |
93
|
|
|
|
94
|
|
|
/** |
95
|
|
|
* Create a new instance of the config class using a JSON file path. |
96
|
|
|
* |
97
|
|
|
* @param string $configFilePath Path to the JSON File |
98
|
|
|
* @throws \RuntimeException |
99
|
|
|
* @return \Phinx\Config\Config |
100
|
2 |
|
*/ |
101
|
|
View Code Duplication |
public static function fromJson($configFilePath) |
|
|
|
|
102
|
2 |
|
{ |
103
|
2 |
|
$configArray = json_decode(file_get_contents($configFilePath), true); |
104
|
1 |
|
if (!is_array($configArray)) { |
105
|
1 |
|
throw new \RuntimeException(sprintf( |
106
|
|
|
'File \'%s\' must be valid JSON', |
107
|
1 |
|
$configFilePath |
108
|
|
|
)); |
109
|
1 |
|
} |
110
|
|
|
|
111
|
|
|
return new static($configArray, $configFilePath); |
112
|
|
|
} |
113
|
|
|
|
114
|
|
|
/** |
115
|
|
|
* Create a new instance of the config class using a PHP file path. |
116
|
|
|
* |
117
|
|
|
* @param string $configFilePath Path to the PHP File |
118
|
|
|
* @throws \RuntimeException |
119
|
3 |
|
* @return \Phinx\Config\Config |
120
|
|
|
*/ |
121
|
3 |
View Code Duplication |
public static function fromPhp($configFilePath) |
|
|
|
|
122
|
|
|
{ |
123
|
3 |
|
ob_start(); |
124
|
|
|
/** @noinspection PhpIncludeInspection */ |
125
|
|
|
$configArray = include($configFilePath); |
126
|
3 |
|
|
127
|
|
|
// Hide console output |
128
|
3 |
|
ob_end_clean(); |
129
|
2 |
|
|
130
|
2 |
|
if (!is_array($configArray)) { |
131
|
|
|
throw new \RuntimeException(sprintf( |
132
|
2 |
|
'PHP file \'%s\' must return an array', |
133
|
|
|
$configFilePath |
134
|
|
|
)); |
135
|
1 |
|
} |
136
|
|
|
|
137
|
|
|
return new static($configArray, $configFilePath); |
138
|
|
|
} |
139
|
|
|
|
140
|
|
|
/** |
141
|
25 |
|
* {@inheritdoc} |
142
|
|
|
*/ |
143
|
25 |
|
public function getEnvironments() |
144
|
24 |
|
{ |
145
|
24 |
|
if (isset($this->values) && isset($this->values['environments'])) { |
146
|
24 |
|
$environments = []; |
147
|
24 |
|
foreach ($this->values['environments'] as $key => $value) { |
148
|
24 |
|
if (is_array($value)) { |
149
|
24 |
|
$environments[$key] = $value; |
150
|
|
|
} |
151
|
24 |
|
} |
152
|
|
|
|
153
|
|
|
return $environments; |
154
|
1 |
|
} |
155
|
|
|
|
156
|
|
|
return null; |
157
|
|
|
} |
158
|
|
|
|
159
|
|
|
/** |
160
|
25 |
|
* {@inheritdoc} |
161
|
|
|
*/ |
162
|
25 |
|
public function getEnvironment($name) |
163
|
|
|
{ |
164
|
25 |
|
$environments = $this->getEnvironments(); |
165
|
21 |
|
|
166
|
21 |
|
if (isset($environments[$name])) { |
167
|
21 |
|
if (isset($this->values['environments']['default_migration_table'])) { |
168
|
21 |
|
$environments[$name]['default_migration_table'] = |
169
|
|
|
$this->values['environments']['default_migration_table']; |
170
|
21 |
|
} |
171
|
|
|
|
172
|
|
|
return $environments[$name]; |
173
|
5 |
|
} |
174
|
|
|
|
175
|
|
|
return null; |
176
|
|
|
} |
177
|
|
|
|
178
|
|
|
/** |
179
|
9 |
|
* {@inheritdoc} |
180
|
|
|
*/ |
181
|
9 |
|
public function hasEnvironment($name) |
182
|
|
|
{ |
183
|
|
|
return ($this->getEnvironment($name) !== null); |
184
|
|
|
} |
185
|
|
|
|
186
|
|
|
/** |
187
|
20 |
|
* {@inheritdoc} |
188
|
|
|
*/ |
189
|
|
|
public function getDefaultEnvironment() |
190
|
20 |
|
{ |
191
|
20 |
|
// The $PHINX_ENVIRONMENT variable overrides all other default settings |
192
|
2 |
|
$env = getenv('PHINX_ENVIRONMENT'); |
193
|
1 |
|
if (!empty($env)) { |
194
|
|
|
if ($this->hasEnvironment($env)) { |
195
|
|
|
return $env; |
196
|
1 |
|
} |
197
|
1 |
|
|
198
|
|
|
throw new \RuntimeException(sprintf( |
199
|
1 |
|
'The environment configuration (read from $PHINX_ENVIRONMENT) for \'%s\' is missing', |
200
|
|
|
$env |
201
|
|
|
)); |
202
|
|
|
} |
203
|
|
|
|
204
|
19 |
|
// if the user has configured a default database then use it, |
205
|
17 |
|
// providing it actually exists! |
206
|
16 |
|
if (isset($this->values['environments']['default_database'])) { |
207
|
|
|
if ($this->getEnvironment($this->values['environments']['default_database'])) { |
208
|
|
|
return $this->values['environments']['default_database']; |
209
|
1 |
|
} |
210
|
1 |
|
|
211
|
1 |
|
throw new \RuntimeException(sprintf( |
212
|
1 |
|
'The environment configuration for \'%s\' is missing', |
213
|
|
|
$this->values['environments']['default_database'] |
214
|
|
|
)); |
215
|
|
|
} |
216
|
2 |
|
|
217
|
1 |
|
// else default to the first available one |
218
|
1 |
|
if (is_array($this->getEnvironments()) && count($this->getEnvironments()) > 0) { |
219
|
|
|
$names = array_keys($this->getEnvironments()); |
220
|
|
|
|
221
|
1 |
|
return $names[0]; |
222
|
|
|
} |
223
|
|
|
|
224
|
|
|
throw new \RuntimeException('Could not find a default environment'); |
225
|
|
|
} |
226
|
|
|
|
227
|
7 |
|
/** |
228
|
|
|
* {@inheritdoc} |
229
|
7 |
|
*/ |
230
|
|
|
public function getAlias($alias) |
231
|
|
|
{ |
232
|
|
|
return !empty($this->values['aliases'][$alias]) ? $this->values['aliases'][$alias] : null; |
233
|
|
|
} |
234
|
|
|
|
235
|
448 |
|
/** |
236
|
|
|
* {@inheritdoc} |
237
|
448 |
|
*/ |
238
|
|
|
public function getAliases() |
239
|
|
|
{ |
240
|
|
|
return !empty($this->values['aliases']) ? $this->values['aliases'] : null; |
241
|
|
|
} |
242
|
|
|
|
243
|
423 |
|
/** |
244
|
|
|
* {@inheritdoc} |
245
|
423 |
|
*/ |
246
|
1 |
|
public function getConfigFilePath() |
247
|
|
|
{ |
248
|
|
|
return $this->configFilePath; |
249
|
422 |
|
} |
250
|
219 |
|
|
251
|
219 |
|
/** |
252
|
|
|
* {@inheritdoc} |
253
|
422 |
|
*/ |
254
|
|
View Code Duplication |
public function getMigrationPaths() |
|
|
|
|
255
|
|
|
{ |
256
|
|
|
if (!isset($this->values['paths']['migrations'])) { |
257
|
|
|
throw new \UnexpectedValueException('Migrations path missing from config file'); |
258
|
|
|
} |
259
|
|
|
|
260
|
|
|
if (is_string($this->values['paths']['migrations'])) { |
261
|
|
|
$this->values['paths']['migrations'] = [$this->values['paths']['migrations']]; |
262
|
14 |
|
} |
263
|
|
|
|
264
|
14 |
|
return $this->values['paths']['migrations']; |
265
|
|
|
} |
266
|
14 |
|
|
267
|
|
|
/** |
268
|
|
|
* Gets the base class name for migrations. |
269
|
|
|
* |
270
|
|
|
* @param bool $dropNamespace Return the base migration class name without the namespace. |
271
|
|
|
* @return string |
272
|
48 |
|
*/ |
273
|
|
|
public function getMigrationBaseClassName($dropNamespace = true) |
274
|
48 |
|
{ |
275
|
28 |
|
$className = !isset($this->values['migration_base_class']) ? 'Phinx\Migration\AbstractMigration' : $this->values['migration_base_class']; |
276
|
|
|
|
277
|
|
|
return $dropNamespace ? substr(strrchr($className, '\\'), 1) ?: $className : $className; |
278
|
20 |
|
} |
279
|
13 |
|
|
280
|
13 |
|
/** |
281
|
|
|
* {@inheritdoc} |
282
|
20 |
|
*/ |
283
|
|
View Code Duplication |
public function getSeedPaths() |
|
|
|
|
284
|
|
|
{ |
285
|
|
|
if (!isset($this->values['paths']['seeds'])) { |
286
|
|
|
throw new \UnexpectedValueException('Seeds path missing from config file'); |
287
|
|
|
} |
288
|
|
|
|
289
|
|
|
if (is_string($this->values['paths']['seeds'])) { |
290
|
14 |
|
$this->values['paths']['seeds'] = [$this->values['paths']['seeds']]; |
291
|
|
|
} |
292
|
14 |
|
|
293
|
13 |
|
return $this->values['paths']['seeds']; |
294
|
|
|
} |
295
|
|
|
|
296
|
1 |
|
/** |
297
|
|
|
* Get the template file name. |
298
|
|
|
* |
299
|
|
|
* @return string|false |
300
|
|
|
*/ |
301
|
|
View Code Duplication |
public function getTemplateFile() |
|
|
|
|
302
|
|
|
{ |
303
|
|
|
if (!isset($this->values['templates']['file'])) { |
304
|
14 |
|
return false; |
305
|
|
|
} |
306
|
14 |
|
|
307
|
10 |
|
return $this->values['templates']['file']; |
308
|
|
|
} |
309
|
|
|
|
310
|
4 |
|
/** |
311
|
|
|
* Get the template class name. |
312
|
|
|
* |
313
|
|
|
* @return string|false |
314
|
|
|
*/ |
315
|
|
View Code Duplication |
public function getTemplateClass() |
|
|
|
|
316
|
|
|
{ |
317
|
|
|
if (!isset($this->values['templates']['class'])) { |
318
|
384 |
|
return false; |
319
|
|
|
} |
320
|
384 |
|
|
321
|
162 |
|
return $this->values['templates']['class']; |
322
|
|
|
} |
323
|
|
|
|
324
|
222 |
|
/** |
325
|
|
|
* Get the version order. |
326
|
|
|
* |
327
|
|
|
* @return string |
328
|
|
|
*/ |
329
|
|
|
public function getVersionOrder() |
330
|
|
|
{ |
331
|
|
|
if (!isset($this->values['version_order'])) { |
332
|
357 |
|
return self::VERSION_ORDER_CREATION_TIME; |
333
|
|
|
} |
334
|
357 |
|
|
335
|
|
|
return $this->values['version_order']; |
336
|
357 |
|
} |
337
|
|
|
|
338
|
|
|
/** |
339
|
|
|
* Is version order creation time? |
340
|
|
|
* |
341
|
|
|
* @return bool |
342
|
|
|
*/ |
343
|
|
|
public function isVersionOrderCreationTime() |
344
|
|
|
{ |
345
|
|
|
$versionOrder = $this->getVersionOrder(); |
346
|
|
|
|
347
|
448 |
|
return $versionOrder == self::VERSION_ORDER_CREATION_TIME; |
348
|
|
|
} |
349
|
|
|
|
350
|
|
|
/** |
351
|
448 |
|
* Get the bootstrap file path |
352
|
448 |
|
* |
353
|
448 |
|
* @return string|false |
354
|
2 |
|
*/ |
355
|
2 |
|
public function getBootstrapFile() |
356
|
448 |
|
{ |
357
|
|
|
if (!isset($this->values['paths']['bootstrap'])) { |
358
|
|
|
return false; |
359
|
448 |
|
} |
360
|
448 |
|
|
361
|
|
|
return $this->values['paths']['bootstrap']; |
362
|
|
|
} |
363
|
448 |
|
|
364
|
|
|
/** |
365
|
|
|
* Replace tokens in the specified array. |
366
|
|
|
* |
367
|
|
|
* @param array $arr Array to replace |
368
|
|
|
* @return array |
369
|
|
|
*/ |
370
|
|
|
protected function replaceTokens(array $arr) |
371
|
|
|
{ |
372
|
|
|
// Get environment variables |
373
|
448 |
|
// $_ENV is empty because variables_order does not include it normally |
374
|
|
|
$tokens = []; |
375
|
448 |
|
foreach ($_SERVER as $varname => $varvalue) { |
376
|
448 |
|
if (0 === strpos($varname, 'PHINX_')) { |
377
|
447 |
|
$tokens['%%' . $varname . '%%'] = $varvalue; |
378
|
446 |
|
} |
379
|
446 |
|
} |
380
|
|
|
|
381
|
446 |
|
// Phinx defined tokens (override env tokens) |
382
|
446 |
|
$tokens['%%PHINX_CONFIG_PATH%%'] = $this->getConfigFilePath(); |
383
|
446 |
|
$tokens['%%PHINX_CONFIG_DIR%%'] = dirname($this->getConfigFilePath()); |
384
|
446 |
|
|
385
|
446 |
|
// Recurse the array and replace tokens |
386
|
446 |
|
return $this->recurseArrayForTokens($arr, $tokens); |
387
|
|
|
} |
388
|
43 |
|
|
389
|
448 |
|
/** |
390
|
448 |
|
* Recurse an array for the specified tokens and replace them. |
391
|
|
|
* |
392
|
|
|
* @param array $arr Array to recurse |
393
|
|
|
* @param array $tokens Array of tokens to search for |
394
|
|
|
* @return array |
395
|
|
|
*/ |
396
|
213 |
|
protected function recurseArrayForTokens($arr, $tokens) |
397
|
|
|
{ |
398
|
213 |
|
$out = []; |
399
|
213 |
|
foreach ($arr as $name => $value) { |
400
|
|
|
if (is_array($value)) { |
401
|
|
|
$out[$name] = $this->recurseArrayForTokens($value, $tokens); |
402
|
|
|
continue; |
403
|
|
|
} |
404
|
2 |
|
if (is_string($value)) { |
405
|
|
|
foreach ($tokens as $token => $tval) { |
406
|
2 |
|
$value = str_replace($token, $tval, $value); |
407
|
1 |
|
} |
408
|
|
|
$out[$name] = $value; |
409
|
|
|
continue; |
410
|
1 |
|
} |
411
|
|
|
$out[$name] = $value; |
412
|
|
|
} |
413
|
|
|
|
414
|
|
|
return $out; |
415
|
|
|
} |
416
|
1 |
|
|
417
|
|
|
/** |
418
|
1 |
|
* {@inheritdoc} |
419
|
|
|
*/ |
420
|
|
|
public function offsetSet($id, $value) |
421
|
|
|
{ |
422
|
|
|
$this->values[$id] = $value; |
423
|
|
|
} |
424
|
1 |
|
|
425
|
|
|
/** |
426
|
1 |
|
* {@inheritdoc} |
427
|
1 |
|
*/ |
428
|
|
|
public function offsetGet($id) |
429
|
|
|
{ |
430
|
|
|
if (!array_key_exists($id, $this->values)) { |
431
|
|
|
throw new \InvalidArgumentException(sprintf('Identifier "%s" is not defined.', $id)); |
432
|
|
|
} |
433
|
|
|
|
434
|
|
|
return $this->values[$id] instanceof \Closure ? $this->values[$id]($this) : $this->values[$id]; |
435
|
|
|
} |
436
|
|
|
|
437
|
|
|
/** |
438
|
|
|
* {@inheritdoc} |
439
|
|
|
*/ |
440
|
|
|
public function offsetExists($id) |
441
|
|
|
{ |
442
|
|
|
return isset($this->values[$id]); |
443
|
|
|
} |
444
|
|
|
|
445
|
|
|
/** |
446
|
|
|
* {@inheritdoc} |
447
|
|
|
*/ |
448
|
|
|
public function offsetUnset($id) |
449
|
|
|
{ |
450
|
|
|
unset($this->values[$id]); |
451
|
|
|
} |
452
|
|
|
} |
453
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.