Completed
Push — master ( 94018a...6a6ebc )
by AD
13s
created

Config::fromJson()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 7

Duplication

Lines 11
Ratio 100 %

Code Coverage

Tests 7
CRAP Score 2

Importance

Changes 0
Metric Value
dl 11
loc 11
ccs 7
cts 7
cp 1
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 7
nc 2
nop 1
crap 2
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 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
        return new static($configArray, $configFilePath);
91
    }
92
93
    /**
94
     * Create a new instance of the config class using a JSON file path.
95
     *
96
     * @param  string $configFilePath Path to the JSON File
97
     * @throws \RuntimeException
98
     * @return Config
99
     */
100 2 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...
101
    {
102 2
        $configArray = json_decode(file_get_contents($configFilePath), true);
103 2
        if (!is_array($configArray)) {
104 1
            throw new \RuntimeException(sprintf(
105 1
                'File \'%s\' must be valid JSON',
106
                $configFilePath
107 1
            ));
108
        }
109 1
        return new static($configArray, $configFilePath);
110
    }
111
112
    /**
113
     * Create a new instance of the config class using a PHP file path.
114
     *
115
     * @param  string $configFilePath Path to the PHP File
116
     * @throws \RuntimeException
117
     * @return Config
118
     */
119 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...
120
    {
121 3
        ob_start();
122
        /** @noinspection PhpIncludeInspection */
123 3
        $configArray = include($configFilePath);
124
125
        // Hide console output
126 3
        ob_end_clean();
127
128 3
        if (!is_array($configArray)) {
129 2
            throw new \RuntimeException(sprintf(
130 2
                'PHP file \'%s\' must return an array',
131
                $configFilePath
132 2
            ));
133
        }
134
135 1
        return new static($configArray, $configFilePath);
136
    }
137
138
    /**
139
     * {@inheritdoc}
140
     */
141 25
    public function getEnvironments()
142
    {
143 25
        if (isset($this->values) && isset($this->values['environments'])) {
144 24
            $environments = [];
145 24
            foreach ($this->values['environments'] as $key => $value) {
146 24
                if (is_array($value)) {
147 24
                    $environments[$key] = $value;
148 24
                }
149 24
            }
150
151 24
            return $environments;
152
        }
153
154 1
        return null;
155
    }
156
157
    /**
158
     * {@inheritdoc}
159
     */
160 25
    public function getEnvironment($name)
161
    {
162 25
        $environments = $this->getEnvironments();
163
164 25
        if (isset($environments[$name])) {
165 21
            if (isset($this->values['environments']['default_migration_table'])) {
166 21
                $environments[$name]['default_migration_table'] =
167 21
                    $this->values['environments']['default_migration_table'];
168 21
            }
169
170 21
            return $environments[$name];
171
        }
172
173 5
        return null;
174
    }
175
176
    /**
177
     * {@inheritdoc}
178
     */
179 9
    public function hasEnvironment($name)
180
    {
181 9
        return ($this->getEnvironment($name) !== null);
182
    }
183
184
    /**
185
     * {@inheritdoc}
186
     */
187 20
    public function getDefaultEnvironment()
188
    {
189
        // The $PHINX_ENVIRONMENT variable overrides all other default settings
190 20
        $env = getenv('PHINX_ENVIRONMENT');
191 20
        if (!empty($env)) {
192 2
            if ($this->hasEnvironment($env)) {
193 1
                return $env;
194
            }
195
196 1
            throw new \RuntimeException(sprintf(
197 1
                'The environment configuration (read from $PHINX_ENVIRONMENT) for \'%s\' is missing',
198
                $env
199 1
            ));
200
        }
201
202
        // if the user has configured a default database then use it,
203
        // providing it actually exists!
204 19
        if (isset($this->values['environments']['default_database'])) {
205 17
            if ($this->getEnvironment($this->values['environments']['default_database'])) {
206 16
                return $this->values['environments']['default_database'];
207
            }
208
209 1
            throw new \RuntimeException(sprintf(
210 1
                'The environment configuration for \'%s\' is missing',
211 1
                $this->values['environments']['default_database']
212 1
            ));
213
        }
214
215
        // else default to the first available one
216 2
        if (is_array($this->getEnvironments()) && count($this->getEnvironments()) > 0) {
217 1
            $names = array_keys($this->getEnvironments());
218 1
            return $names[0];
219
        }
220
221 1
        throw new \RuntimeException('Could not find a default environment');
222
    }
223
224
    /**
225
     * {@inheritdoc}
226
     */
227 7
    public function getAlias($alias)
228
    {
229 7
        return !empty($this->values['aliases'][$alias]) ? $this->values['aliases'][$alias] : null;
230
    }
231
232
    /**
233
     * {@inheritdoc}
234
     */
235 448
    public function getConfigFilePath()
236
    {
237 448
        return $this->configFilePath;
238
    }
239
240
    /**
241
     * {@inheritdoc}
242
     */
243 423 View Code Duplication
    public function getMigrationPaths()
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...
244
    {
245 423
        if (!isset($this->values['paths']['migrations'])) {
246 1
            throw new \UnexpectedValueException('Migrations path missing from config file');
247
        }
248
249 422
        if (is_string($this->values['paths']['migrations'])) {
250 219
            $this->values['paths']['migrations'] = [$this->values['paths']['migrations']];
251 219
        }
252
253 422
        return $this->values['paths']['migrations'];
254
    }
255
256
    /**
257
     * Gets the base class name for migrations.
258
     *
259
     * @param boolean $dropNamespace Return the base migration class name without the namespace.
260
     * @return string
261
     */
262 14
    public function getMigrationBaseClassName($dropNamespace = true)
263
    {
264 14
        $className = !isset($this->values['migration_base_class']) ? 'Phinx\Migration\AbstractMigration' : $this->values['migration_base_class'];
265
266 14
        return $dropNamespace ? substr(strrchr($className, '\\'), 1) ?: $className : $className;
267
    }
268
269
    /**
270
     * {@inheritdoc}
271
     */
272 48 View Code Duplication
    public function getSeedPaths()
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...
273
    {
274 48
        if (!isset($this->values['paths']['seeds'])) {
275 28
            throw new \UnexpectedValueException('Seeds path missing from config file');
276
        }
277
278 20
        if (is_string($this->values['paths']['seeds'])) {
279 13
            $this->values['paths']['seeds'] = [$this->values['paths']['seeds']];
280 13
        }
281
282 20
        return $this->values['paths']['seeds'];
283
    }
284
285
    /**
286
     * Get the template file name.
287
     *
288
     * @return string|false
289
     */
290 14 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...
291
    {
292 14
        if (!isset($this->values['templates']['file'])) {
293 13
            return false;
294
        }
295
296 1
        return $this->values['templates']['file'];
297
    }
298
299
    /**
300
     * Get the template class name.
301
     *
302
     * @return string|false
303
     */
304 14 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...
305
    {
306 14
        if (!isset($this->values['templates']['class'])) {
307 10
            return false;
308
        }
309
310 4
        return $this->values['templates']['class'];
311
    }
312
313
    /**
314
     * Get the version order.
315
     *
316
     * @return string
317
     */
318 384
    public function getVersionOrder()
319
    {
320 384
        if (!isset($this->values['version_order'])) {
321 162
            return self::VERSION_ORDER_CREATION_TIME;
322
        }
323
324 222
        return $this->values['version_order'];
325
    }
326
327
    /**
328
     * Is version order creation time?
329
     *
330
     * @return boolean
331
     */
332 357
    public function isVersionOrderCreationTime()
333
    {
334 357
        $versionOrder = $this->getVersionOrder();
335
336 357
        return $versionOrder == self::VERSION_ORDER_CREATION_TIME;
337
    }
338
339
340
341
    /**
342
     * Replace tokens in the specified array.
343
     *
344
     * @param array $arr Array to replace
345
     * @return array
346
     */
347 448
    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...
348
    {
349
        // Get environment variables
350
        // $_ENV is empty because variables_order does not include it normally
351 448
        $tokens = [];
352 448
        foreach ($_SERVER as $varname => $varvalue) {
353 448
            if (0 === strpos($varname, 'PHINX_')) {
354 2
                $tokens['%%' . $varname . '%%'] = $varvalue;
355 2
            }
356 448
        }
357
358
        // Phinx defined tokens (override env tokens)
359 448
        $tokens['%%PHINX_CONFIG_PATH%%'] = $this->getConfigFilePath();
360 448
        $tokens['%%PHINX_CONFIG_DIR%%'] = dirname($this->getConfigFilePath());
361
362
        // Recurse the array and replace tokens
363 448
        return $this->recurseArrayForTokens($arr, $tokens);
364
    }
365
366
    /**
367
     * Recurse an array for the specified tokens and replace them.
368
     *
369
     * @param array $arr Array to recurse
370
     * @param array $tokens Array of tokens to search for
371
     * @return array
372
     */
373 448
    protected function recurseArrayForTokens($arr, $tokens)
374
    {
375 448
        $out = [];
376 448
        foreach ($arr as $name => $value) {
377 447
            if (is_array($value)) {
378 446
                $out[$name] = $this->recurseArrayForTokens($value, $tokens);
379 446
                continue;
380
            }
381 446
            if (is_string($value)) {
382 446
                foreach ($tokens as $token => $tval) {
383 446
                    $value = str_replace($token, $tval, $value);
384 446
                }
385 446
                $out[$name] = $value;
386 446
                continue;
387
            }
388 43
            $out[$name] = $value;
389 448
        }
390 448
        return $out;
391
    }
392
393
    /**
394
     * {@inheritdoc}
395
     */
396 213
    public function offsetSet($id, $value)
397
    {
398 213
        $this->values[$id] = $value;
399 213
    }
400
401
    /**
402
     * {@inheritdoc}
403
     */
404 2
    public function offsetGet($id)
405
    {
406 2
        if (!array_key_exists($id, $this->values)) {
407 1
            throw new \InvalidArgumentException(sprintf('Identifier "%s" is not defined.', $id));
408
        }
409
410 1
        return $this->values[$id] instanceof \Closure ? $this->values[$id]($this) : $this->values[$id];
411
    }
412
413
    /**
414
     * {@inheritdoc}
415
     */
416 1
    public function offsetExists($id)
417
    {
418 1
        return isset($this->values[$id]);
419
    }
420
421
    /**
422
     * {@inheritdoc}
423
     */
424 1
    public function offsetUnset($id)
425
    {
426 1
        unset($this->values[$id]);
427 1
    }
428
}
429