Completed
Pull Request — master (#1241)
by
unknown
02:14
created

Config::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 5
ccs 4
cts 4
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 2
crap 1
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)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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 getStorageConfigs(array $envOptions)
182
    {
183
184
        $configs = [];
185
186
        if (isset($envOptions['default_database'])) {
187 20
            unset($envOptions['default_database']);
188
        }
189
190 20
        if (isset($envOptions['default_migration_table'])) {
191 20
            unset($envOptions['default_migration_table']);
192 2
        }
193 1
194
        if (count($envOptions) > 0) {
195
            foreach ($envOptions as $dbRef => $adapterOptions) {
196 1
                if (!is_array($adapterOptions)) {
197 1
                    $configs [$dbRef]= $envOptions;
198
                    break;
199 1
                } else {
200
                    $configs [$dbRef]= array_merge($adapterOptions, ['dbRef' => $dbRef]);
201
                }
202
            }
203
        }
204 19
205 17
        return $configs;
206 16
    }
207
208
    /**
209 1
     * {@inheritdoc}
210 1
     */
211 1
    public function hasEnvironment($name)
212 1
    {
213
        return ($this->getEnvironment($name) !== null);
214
    }
215
216 2
    /**
217 1
     * {@inheritdoc}
218 1
     */
219
    public function getDefaultEnvironment()
220
    {
221 1
        // The $PHINX_ENVIRONMENT variable overrides all other default settings
222
        $env = getenv('PHINX_ENVIRONMENT');
223
        if (!empty($env)) {
224
            if ($this->hasEnvironment($env)) {
225
                return $env;
226
            }
227 7
228
            throw new \RuntimeException(sprintf(
229 7
                'The environment configuration (read from $PHINX_ENVIRONMENT) for \'%s\' is missing',
230
                $env
231
            ));
232
        }
233
234
        // if the user has configured a default database then use it,
235 448
        // providing it actually exists!
236
        if (isset($this->values['environments']['default_database'])) {
237 448
            if ($this->getEnvironment($this->values['environments']['default_database'])) {
238
                return $this->values['environments']['default_database'];
239
            }
240
241
            throw new \RuntimeException(sprintf(
242
                'The environment configuration for \'%s\' is missing',
243 423
                $this->values['environments']['default_database']
244
            ));
245 423
        }
246 1
247
        // else default to the first available one
248
        if (is_array($this->getEnvironments()) && count($this->getEnvironments()) > 0) {
249 422
            $names = array_keys($this->getEnvironments());
250 219
251 219
            return $names[0];
252
        }
253 422
254
        throw new \RuntimeException('Could not find a default environment');
255
    }
256
257
    /**
258
     * {@inheritdoc}
259
     */
260
    public function getAlias($alias)
261
    {
262 14
        return !empty($this->values['aliases'][$alias]) ? $this->values['aliases'][$alias] : null;
263
    }
264 14
265
    /**
266 14
     * {@inheritdoc}
267
     */
268
    public function getConfigFilePath()
269
    {
270
        return $this->configFilePath;
271
    }
272 48
273
    /**
274 48
     * {@inheritdoc}
275 28
     */
276 View Code Duplication
    public function getMigrationPaths($environment = null, $dbReference = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
277
    {
278 20
        $paths = [];
279 13
280 13
        if (!isset($this->values['paths']['migrations'])) {
281
            throw new \UnexpectedValueException('Default migrations path missing from config file');
282 20
        }
283
284
        if (is_string($this->values['paths']['migrations'])) {
285
            $this->values['paths']['migrations'] = [$this->values['paths']['migrations']];
286
        }
287
288
        if ($environment !== null && $dbReference !== null) {
289
            $environment = $this->getEnvironment($environment);
290 14
            if (isset($environment[$dbReference]['paths']['migrations'])) {
291
                if (!is_array($environment[$dbReference]['paths']['migrations'])) {
292 14
                    return [$environment[$dbReference]['paths']['migrations']];
293 13
                } else {
294
                    foreach ($environment[$dbReference]['paths']['migrations'] as $namespace => $migrationPath) {
295
                        $paths[$namespace]= $migrationPath;
296 1
                    }
297
                    if (count($paths) > 0) {
298
                        $this->values['paths']['migrations']= $paths;
299
                    }
300
                }
301
            }
302
        } elseif (is_null($environment) && is_null($dbReference)) {
303
            if (isset($this->values['environments']) && is_array($this->values['environments'])) {
304 14
                $environments = array_keys($this->values['environments']);
305
306 14
                foreach ($environments as $env) {
307 10
                    if (is_array($this->values['environments'][$env])) {
308
                        foreach ($this->values['environments'][$env] as $dbReference => $properties) {
309
                            if (!is_array($properties)) {
310 4
                                continue;
311
                            }
312
313
                            if (!is_array($this->values['environments'][$env][$dbReference]['paths']['migrations'])) {
314
                                $paths []= $this->values['environments'][$env][$dbReference]['paths']['migrations'];
315
                            } else {
316
                                foreach ($this->values['environments'][$env][$dbReference]['paths']['migrations'] as $namespace => $migrationPath) {
317
                                    $paths[$namespace]= $migrationPath;
318 384
                                }
319
                            }
320 384
                        }
321 162
                    }
322
                }
323
                if (count($paths) > 0) {
324 222
                    $this->values['paths']['migrations']= $paths;
325
                }
326
            }
327
        }
328
329
        return $this->values['paths']['migrations'];
330
    }
331
332 357
    /**
333
     * Gets the base class name for migrations.
334 357
     *
335
     * @param bool $dropNamespace Return the base migration class name without the namespace.
336 357
     * @return string
337
     */
338
    public function getMigrationBaseClassName($dropNamespace = true)
339
    {
340
        $className = !isset($this->values['migration_base_class']) ? 'Phinx\Migration\AbstractMigration' : $this->values['migration_base_class'];
341
342
        return $dropNamespace ? substr(strrchr($className, '\\'), 1) ?: $className : $className;
343
    }
344
345
    /**
346
     * {@inheritdoc}
347 448
     */
348 View Code Duplication
    public function getSeedPaths($environment = null, $dbReference = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
349
    {
350
351 448
        $paths = [];
352 448
353 448
        if (!isset($this->values['paths']['seeds'])) {
354 2
            throw new \UnexpectedValueException('Seeds path missing from config file');
355 2
        }
356 448
357
        if (is_string($this->values['paths']['seeds'])) {
358
            $this->values['paths']['seeds'] = [$this->values['paths']['seeds']];
359 448
        }
360 448
361
        if ($environment !== null && $dbReference !== null) {
362
            $environment = $this->getEnvironment($environment);
363 448
            if (isset($environment[$dbReference]['paths']['seeds'])) {
364
                if (!is_array($environment[$dbReference]['paths']['seeds'])) {
365
                    return [$environment[$dbReference]['paths']['seeds']];
366
                } else {
367
                    foreach ($environment[$dbReference]['paths']['seeds'] as $namespace => $seedPath) {
368
                        $paths[$namespace]= $seedPath;
369
                    }
370
                    if (count($paths) > 0) {
371
                        $this->values['paths']['seeds']= $paths;
372
                    }
373 448
                }
374
            }
375 448
        } elseif (is_null($environment) && is_null($dbReference)) {
376 448
            if (isset($this->values['environments']) && is_array($this->values['environments'])) {
377 447
                $environments = array_keys($this->values['environments']);
378 446
                foreach ($environments as $env) {
379 446
                    if (is_array($this->values['environments'][$env])) {
380
                        foreach ($this->values['environments'][$env] as $dbReference => $properties) {
381 446
                            if (!is_array($properties)) {
382 446
                                continue;
383 446
                            }
384 446
385 446
                            if (!is_array($this->values['environments'][$env][$dbReference]['paths']['seeds'])) {
386 446
                                $paths []= $this->values['environments'][$env][$dbReference]['paths']['seeds'];
387
                            } else {
388 43
                                foreach ($this->values['environments'][$env][$dbReference]['paths']['seeds'] as $namespace => $migrationPath) {
389 448
                                    $paths[$namespace]= $migrationPath;
390 448
                                }
391
                            }
392
                        }
393
                    }
394
                }
395
            }
396 213
            if (count($paths) > 0) {
397
                $this->values['paths']['seeds']= $paths;
398 213
            }
399 213
        }
400
401
        return $this->values['paths']['seeds'];
402
    }
403
404 2
    /**
405
     * Get the template file name.
406 2
     *
407 1
     * @return string|false
408
     */
409 View Code Duplication
    public function getTemplateFile()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
410 1
    {
411
        if (!isset($this->values['templates']['file'])) {
412
            return false;
413
        }
414
415
        return $this->values['templates']['file'];
416 1
    }
417
418 1
    /**
419
     * Get the template class name.
420
     *
421
     * @return string|false
422
     */
423 View Code Duplication
    public function getTemplateClass()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
424 1
    {
425
        if (!isset($this->values['templates']['class'])) {
426 1
            return false;
427 1
        }
428
429
        return $this->values['templates']['class'];
430
    }
431
432
    /**
433
     * Get the version order.
434
     *
435
     * @return string
436
     */
437
    public function getVersionOrder()
438
    {
439
        if (!isset($this->values['version_order'])) {
440
            return self::VERSION_ORDER_CREATION_TIME;
441
        }
442
443
        return $this->values['version_order'];
444
    }
445
446
    /**
447
     * Is version order creation time?
448
     *
449
     * @return bool
450
     */
451
    public function isVersionOrderCreationTime()
452
    {
453
        $versionOrder = $this->getVersionOrder();
454
455
        return $versionOrder == self::VERSION_ORDER_CREATION_TIME;
456
    }
457
458
    /**
459
     * Replace tokens in the specified array.
460
     *
461
     * @param array $arr Array to replace
462
     * @return array
463
     */
464
    protected function replaceTokens(array $arr)
0 ignored issues
show
Coding Style introduced by
replaceTokens uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
465
    {
466
        // Get environment variables
467
        // $_ENV is empty because variables_order does not include it normally
468
        $tokens = [];
469
        foreach ($_SERVER as $varname => $varvalue) {
470
            if (0 === strpos($varname, 'PHINX_')) {
471
                $tokens['%%' . $varname . '%%'] = $varvalue;
472
            }
473
        }
474
475
        // Phinx defined tokens (override env tokens)
476
        $tokens['%%PHINX_CONFIG_PATH%%'] = $this->getConfigFilePath();
477
        $tokens['%%PHINX_CONFIG_DIR%%'] = dirname($this->getConfigFilePath());
478
479
        // Recurse the array and replace tokens
480
        return $this->recurseArrayForTokens($arr, $tokens);
481
    }
482
483
    /**
484
     * Recurse an array for the specified tokens and replace them.
485
     *
486
     * @param array $arr Array to recurse
487
     * @param array $tokens Array of tokens to search for
488
     * @return array
489
     */
490
    protected function recurseArrayForTokens($arr, $tokens)
491
    {
492
        $out = [];
493
        foreach ($arr as $name => $value) {
494
            if (is_array($value)) {
495
                $out[$name] = $this->recurseArrayForTokens($value, $tokens);
496
                continue;
497
            }
498
            if (is_string($value)) {
499
                foreach ($tokens as $token => $tval) {
500
                    $value = str_replace($token, $tval, $value);
501
                }
502
                $out[$name] = $value;
503
                continue;
504
            }
505
            $out[$name] = $value;
506
        }
507
508
        return $out;
509
    }
510
511
    /**
512
     * {@inheritdoc}
513
     */
514
    public function offsetSet($id, $value)
515
    {
516
        $this->values[$id] = $value;
517
    }
518
519
    /**
520
     * {@inheritdoc}
521
     */
522
    public function offsetGet($id)
523
    {
524
        if (!array_key_exists($id, $this->values)) {
525
            throw new \InvalidArgumentException(sprintf('Identifier "%s" is not defined.', $id));
526
        }
527
528
        return $this->values[$id] instanceof \Closure ? $this->values[$id]($this) : $this->values[$id];
529
    }
530
531
    /**
532
     * {@inheritdoc}
533
     */
534
    public function offsetExists($id)
535
    {
536
        return isset($this->values[$id]);
537
    }
538
539
    /**
540
     * {@inheritdoc}
541
     */
542
    public function offsetUnset($id)
543
    {
544
        unset($this->values[$id]);
545
    }
546
}
547