Completed
Push — master ( ba8259...3b74bb )
by AD
18s
created

Configure   B

Complexity

Total Complexity 44

Size/Duplication

Total Lines 456
Duplicated Lines 8.55 %

Coupling/Cohesion

Components 1
Dependencies 5

Importance

Changes 0
Metric Value
dl 39
loc 456
rs 8.8798
c 0
b 0
f 0
wmc 44
lcom 1
cbo 5

18 Methods

Rating   Name   Duplication   Size   Complexity  
B write() 0 21 7
A read() 0 8 2
A check() 0 8 2
A readOrFail() 8 8 2
A delete() 0 4 1
A consumeOrFail() 8 8 2
A consume() 0 16 3
A config() 0 4 1
A configured() 0 13 2
A isConfigured() 0 4 1
A drop() 0 9 2
A load() 0 14 3
A dump() 0 13 4
A _getEngine() 0 11 3
A version() 0 9 2
A store() 11 11 3
A restore() 12 12 3
A clear() 0 6 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Configure often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Configure, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
4
 * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
5
 *
6
 * Licensed under The MIT License
7
 * For full copyright and license information, please see the LICENSE.txt
8
 * Redistributions of files must retain the above copyright notice.
9
 *
10
 * @copyright     Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
11
 * @link          https://cakephp.org CakePHP(tm) Project
12
 * @since         1.0.0
13
 * @license       https://opensource.org/licenses/mit-license.php MIT License
14
 */
15
namespace Cake\Core;
16
17
use Cake\Cache\Cache;
18
use Cake\Core\Configure\ConfigEngineInterface;
19
use Cake\Core\Configure\Engine\PhpConfig;
20
use Cake\Core\Exception\Exception;
21
use Cake\Utility\Hash;
22
use RuntimeException;
23
24
/**
25
 * Configuration class. Used for managing runtime configuration information.
26
 *
27
 * Provides features for reading and writing to the runtime configuration, as well
28
 * as methods for loading additional configuration files or storing runtime configuration
29
 * for future use.
30
 *
31
 * @link https://book.cakephp.org/3.0/en/development/configuration.html
32
 */
33
class Configure
34
{
35
36
    /**
37
     * Array of values currently stored in Configure.
38
     *
39
     * @var array
40
     */
41
    protected static $_values = [
42
        'debug' => false
43
    ];
44
45
    /**
46
     * Configured engine classes, used to load config files from resources
47
     *
48
     * @see \Cake\Core\Configure::load()
49
     * @var \Cake\Core\Configure\ConfigEngineInterface[]
50
     */
51
    protected static $_engines = [];
52
53
    /**
54
     * Flag to track whether or not ini_set exists.
55
     *
56
     * @var bool|null
57
     */
58
    protected static $_hasIniSet;
59
60
    /**
61
     * Used to store a dynamic variable in Configure.
62
     *
63
     * Usage:
64
     * ```
65
     * Configure::write('One.key1', 'value of the Configure::One[key1]');
66
     * Configure::write(['One.key1' => 'value of the Configure::One[key1]']);
67
     * Configure::write('One', [
68
     *     'key1' => 'value of the Configure::One[key1]',
69
     *     'key2' => 'value of the Configure::One[key2]'
70
     * ]);
71
     *
72
     * Configure::write([
73
     *     'One.key1' => 'value of the Configure::One[key1]',
74
     *     'One.key2' => 'value of the Configure::One[key2]'
75
     * ]);
76
     * ```
77
     *
78
     * @param string|array $config The key to write, can be a dot notation value.
79
     * Alternatively can be an array containing key(s) and value(s).
80
     * @param mixed $value Value to set for var
81
     * @return bool True if write was successful
82
     * @link https://book.cakephp.org/3.0/en/development/configuration.html#writing-configuration-data
83
     */
84
    public static function write($config, $value = null)
85
    {
86
        if (!is_array($config)) {
87
            $config = [$config => $value];
88
        }
89
90
        foreach ($config as $name => $value) {
91
            static::$_values = Hash::insert(static::$_values, $name, $value);
0 ignored issues
show
Bug introduced by
It seems like static::$_values can also be of type null; however, Cake\Utility\Hash::insert() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
Documentation Bug introduced by
It seems like \Cake\Utility\Hash::inse..._values, $name, $value) can be null. However, the property $_values is declared as array. Maybe change the type of the property to array|null or add a type check?

Our type inference engine has found an assignment of a scalar value (like a string, an integer or null) to a property which is an array.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.

To type hint that a parameter can be either an array or null, you can set a type hint of array and a default value of null. The PHP interpreter will then accept both an array or null for that parameter.

function aContainsB(array $needle = null, array  $haystack) {
    if (!$needle) {
        return false;
    }

    return array_intersect($haystack, $needle) == $haystack;
}

The function can be called with either null or an array for the parameter $needle but will only accept an array as $haystack.

Loading history...
92
        }
93
94
        if (isset($config['debug'])) {
95
            if (static::$_hasIniSet === null) {
96
                static::$_hasIniSet = function_exists('ini_set');
97
            }
98
            if (static::$_hasIniSet) {
99
                ini_set('display_errors', $config['debug'] ? '1' : '0');
100
            }
101
        }
102
103
        return true;
104
    }
105
106
    /**
107
     * Used to read information stored in Configure. It's not
108
     * possible to store `null` values in Configure.
109
     *
110
     * Usage:
111
     * ```
112
     * Configure::read('Name'); will return all values for Name
113
     * Configure::read('Name.key'); will return only the value of Configure::Name[key]
114
     * ```
115
     *
116
     * @param string|null $var Variable to obtain. Use '.' to access array elements.
117
     * @param mixed $default The return value when the configure does not exist
118
     * @return mixed Value stored in configure, or null.
119
     * @link https://book.cakephp.org/3.0/en/development/configuration.html#reading-configuration-data
120
     */
121
    public static function read($var = null, $default = null)
122
    {
123
        if ($var === null) {
124
            return static::$_values;
125
        }
126
127
        return Hash::get(static::$_values, $var, $default);
128
    }
129
130
    /**
131
     * Returns true if given variable is set in Configure.
132
     *
133
     * @param string $var Variable name to check for
134
     * @return bool True if variable is there
135
     */
136
    public static function check($var)
137
    {
138
        if (empty($var)) {
139
            return false;
140
        }
141
142
        return static::read($var) !== null;
143
    }
144
145
    /**
146
     * Used to get information stored in Configure. It's not
147
     * possible to store `null` values in Configure.
148
     *
149
     * Acts as a wrapper around Configure::read() and Configure::check().
150
     * The configure key/value pair fetched via this method is expected to exist.
151
     * In case it does not an exception will be thrown.
152
     *
153
     * Usage:
154
     * ```
155
     * Configure::readOrFail('Name'); will return all values for Name
156
     * Configure::readOrFail('Name.key'); will return only the value of Configure::Name[key]
157
     * ```
158
     *
159
     * @param string $var Variable to obtain. Use '.' to access array elements.
160
     * @return mixed Value stored in configure.
161
     * @throws \RuntimeException if the requested configuration is not set.
162
     * @link https://book.cakephp.org/3.0/en/development/configuration.html#reading-configuration-data
163
     */
164 View Code Duplication
    public static function readOrFail($var)
165
    {
166
        if (static::check($var) === false) {
167
            throw new RuntimeException(sprintf('Expected configuration key "%s" not found.', $var));
168
        }
169
170
        return static::read($var);
171
    }
172
173
    /**
174
     * Used to delete a variable from Configure.
175
     *
176
     * Usage:
177
     * ```
178
     * Configure::delete('Name'); will delete the entire Configure::Name
179
     * Configure::delete('Name.key'); will delete only the Configure::Name[key]
180
     * ```
181
     *
182
     * @param string $var the var to be deleted
183
     * @return void
184
     * @link https://book.cakephp.org/3.0/en/development/configuration.html#deleting-configuration-data
185
     */
186
    public static function delete($var)
187
    {
188
        static::$_values = Hash::remove(static::$_values, $var);
0 ignored issues
show
Documentation Bug introduced by
It seems like \Cake\Utility\Hash::remove(static::$_values, $var) can be null. However, the property $_values is declared as array. Maybe change the type of the property to array|null or add a type check?

Our type inference engine has found an assignment of a scalar value (like a string, an integer or null) to a property which is an array.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.

To type hint that a parameter can be either an array or null, you can set a type hint of array and a default value of null. The PHP interpreter will then accept both an array or null for that parameter.

function aContainsB(array $needle = null, array  $haystack) {
    if (!$needle) {
        return false;
    }

    return array_intersect($haystack, $needle) == $haystack;
}

The function can be called with either null or an array for the parameter $needle but will only accept an array as $haystack.

Loading history...
189
    }
190
191
    /**
192
     * Used to consume information stored in Configure. It's not
193
     * possible to store `null` values in Configure.
194
     *
195
     * Acts as a wrapper around Configure::consume() and Configure::check().
196
     * The configure key/value pair consumed via this method is expected to exist.
197
     * In case it does not an exception will be thrown.
198
     *
199
     * @param string $var Variable to consume. Use '.' to access array elements.
200
     * @return mixed Value stored in configure.
201
     * @throws \RuntimeException if the requested configuration is not set.
202
     * @since 3.6.0
203
     */
204 View Code Duplication
    public static function consumeOrFail($var)
205
    {
206
        if (static::check($var) === false) {
207
            throw new RuntimeException(sprintf('Expected configuration key "%s" not found.', $var));
208
        }
209
210
        return static::consume($var);
211
    }
212
213
    /**
214
     * Used to read and delete a variable from Configure.
215
     *
216
     * This is primarily used during bootstrapping to move configuration data
217
     * out of configure into the various other classes in CakePHP.
218
     *
219
     * @param string $var The key to read and remove.
220
     * @return array|string|null
221
     */
222
    public static function consume($var)
223
    {
224
        if (strpos($var, '.') === false) {
225
            if (!isset(static::$_values[$var])) {
226
                return null;
227
            }
228
            $value = static::$_values[$var];
229
            unset(static::$_values[$var]);
230
231
            return $value;
232
        }
233
        $value = Hash::get(static::$_values, $var);
234
        static::delete($var);
235
236
        return $value;
237
    }
238
239
    /**
240
     * Add a new engine to Configure. Engines allow you to read configuration
241
     * files in various formats/storage locations. CakePHP comes with two built-in engines
242
     * PhpConfig and IniConfig. You can also implement your own engine classes in your application.
243
     *
244
     * To add a new engine to Configure:
245
     *
246
     * ```
247
     * Configure::config('ini', new IniConfig());
248
     * ```
249
     *
250
     * @param string $name The name of the engine being configured. This alias is used later to
251
     *   read values from a specific engine.
252
     * @param \Cake\Core\Configure\ConfigEngineInterface $engine The engine to append.
253
     * @return void
254
     */
255
    public static function config($name, ConfigEngineInterface $engine)
256
    {
257
        static::$_engines[$name] = $engine;
258
    }
259
260
    /**
261
     * Gets the names of the configured Engine objects.
262
     *
263
     * Checking if a specific engine has been configured with this method is deprecated.
264
     * Use Configure::isConfigured() instead.
265
     *
266
     * @param string|null $name Engine name.
267
     * @return array|bool Array of the configured Engine objects, bool for specific name.
268
     */
269
    public static function configured($name = null)
270
    {
271
        if ($name !== null) {
272
            deprecationWarning(
273
                'Checking for a named engine with configured() is deprecated. ' .
274
                'Use Configure::isConfigured() instead.'
275
            );
276
277
            return isset(static::$_engines[$name]);
278
        }
279
280
        return array_keys(static::$_engines);
281
    }
282
283
    /**
284
     * Returns true if the Engine objects is configured.
285
     *
286
     * @param string $name Engine name.
287
     * @return bool
288
     */
289
    public static function isConfigured($name)
290
    {
291
        return isset(static::$_engines[$name]);
292
    }
293
294
    /**
295
     * Remove a configured engine. This will unset the engine
296
     * and make any future attempts to use it cause an Exception.
297
     *
298
     * @param string $name Name of the engine to drop.
299
     * @return bool Success
300
     */
301
    public static function drop($name)
302
    {
303
        if (!isset(static::$_engines[$name])) {
304
            return false;
305
        }
306
        unset(static::$_engines[$name]);
307
308
        return true;
309
    }
310
311
    /**
312
     * Loads stored configuration information from a resource. You can add
313
     * config file resource engines with `Configure::config()`.
314
     *
315
     * Loaded configuration information will be merged with the current
316
     * runtime configuration. You can load configuration files from plugins
317
     * by preceding the filename with the plugin name.
318
     *
319
     * `Configure::load('Users.user', 'default')`
320
     *
321
     * Would load the 'user' config file using the default config engine. You can load
322
     * app config files by giving the name of the resource you want loaded.
323
     *
324
     * ```
325
     * Configure::load('setup', 'default');
326
     * ```
327
     *
328
     * If using `default` config and no engine has been configured for it yet,
329
     * one will be automatically created using PhpConfig
330
     *
331
     * @param string $key name of configuration resource to load.
332
     * @param string $config Name of the configured engine to use to read the resource identified by $key.
333
     * @param bool $merge if config files should be merged instead of simply overridden
334
     * @return bool False if file not found, true if load successful.
335
     * @link https://book.cakephp.org/3.0/en/development/configuration.html#reading-and-writing-configuration-files
336
     */
337
    public static function load($key, $config = 'default', $merge = true)
338
    {
339
        $engine = static::_getEngine($config);
340
        if (!$engine) {
341
            return false;
342
        }
343
        $values = $engine->read($key);
344
345
        if ($merge) {
346
            $values = Hash::merge(static::$_values, $values);
347
        }
348
349
        return static::write($values);
350
    }
351
352
    /**
353
     * Dump data currently in Configure into $key. The serialization format
354
     * is decided by the config engine attached as $config. For example, if the
355
     * 'default' adapter is a PhpConfig, the generated file will be a PHP
356
     * configuration file loadable by the PhpConfig.
357
     *
358
     * ### Usage
359
     *
360
     * Given that the 'default' engine is an instance of PhpConfig.
361
     * Save all data in Configure to the file `my_config.php`:
362
     *
363
     * ```
364
     * Configure::dump('my_config', 'default');
365
     * ```
366
     *
367
     * Save only the error handling configuration:
368
     *
369
     * ```
370
     * Configure::dump('error', 'default', ['Error', 'Exception'];
371
     * ```
372
     *
373
     * @param string $key The identifier to create in the config adapter.
374
     *   This could be a filename or a cache key depending on the adapter being used.
375
     * @param string $config The name of the configured adapter to dump data with.
376
     * @param array $keys The name of the top-level keys you want to dump.
377
     *   This allows you save only some data stored in Configure.
378
     * @return bool Success
379
     * @throws \Cake\Core\Exception\Exception if the adapter does not implement a `dump` method.
380
     */
381
    public static function dump($key, $config = 'default', $keys = [])
382
    {
383
        $engine = static::_getEngine($config);
384
        if (!$engine) {
385
            throw new Exception(sprintf('There is no "%s" config engine.', $config));
386
        }
387
        $values = static::$_values;
388
        if (!empty($keys) && is_array($keys)) {
389
            $values = array_intersect_key($values, array_flip($keys));
390
        }
391
392
        return (bool)$engine->dump($key, $values);
393
    }
394
395
    /**
396
     * Get the configured engine. Internally used by `Configure::load()` and `Configure::dump()`
397
     * Will create new PhpConfig for default if not configured yet.
398
     *
399
     * @param string $config The name of the configured adapter
400
     * @return \Cake\Core\Configure\ConfigEngineInterface|false Engine instance or false
401
     */
402
    protected static function _getEngine($config)
403
    {
404
        if (!isset(static::$_engines[$config])) {
405
            if ($config !== 'default') {
406
                return false;
407
            }
408
            static::config($config, new PhpConfig());
409
        }
410
411
        return static::$_engines[$config];
412
    }
413
414
    /**
415
     * Used to determine the current version of CakePHP.
416
     *
417
     * Usage
418
     * ```
419
     * Configure::version();
420
     * ```
421
     *
422
     * @return string Current version of CakePHP
423
     */
424
    public static function version()
425
    {
426
        if (!isset(static::$_values['Cake']['version'])) {
427
            $config = require CORE_PATH . 'config/config.php';
428
            static::write($config);
429
        }
430
431
        return static::$_values['Cake']['version'];
432
    }
433
434
    /**
435
     * Used to write runtime configuration into Cache. Stored runtime configuration can be
436
     * restored using `Configure::restore()`. These methods can be used to enable configuration managers
437
     * frontends, or other GUI type interfaces for configuration.
438
     *
439
     * @param string $name The storage name for the saved configuration.
440
     * @param string $cacheConfig The cache configuration to save into. Defaults to 'default'
441
     * @param array|null $data Either an array of data to store, or leave empty to store all values.
442
     * @return bool Success
443
     */
444 View Code Duplication
    public static function store($name, $cacheConfig = 'default', $data = null)
445
    {
446
        if ($data === null) {
447
            $data = static::$_values;
448
        }
449
        if (!class_exists(Cache::class)) {
450
            throw new RuntimeException('You must install cakephp/cache to use Configure::store()');
451
        }
452
453
        return Cache::write($name, $data, $cacheConfig);
454
    }
455
456
    /**
457
     * Restores configuration data stored in the Cache into configure. Restored
458
     * values will overwrite existing ones.
459
     *
460
     * @param string $name Name of the stored config file to load.
461
     * @param string $cacheConfig Name of the Cache configuration to read from.
462
     * @return bool Success.
463
     */
464 View Code Duplication
    public static function restore($name, $cacheConfig = 'default')
465
    {
466
        if (!class_exists(Cache::class)) {
467
            throw new RuntimeException('You must install cakephp/cache to use Configure::restore()');
468
        }
469
        $values = Cache::read($name, $cacheConfig);
470
        if ($values) {
471
            return static::write($values);
472
        }
473
474
        return false;
475
    }
476
477
    /**
478
     * Clear all values stored in Configure.
479
     *
480
     * @return bool success.
481
     */
482
    public static function clear()
483
    {
484
        static::$_values = [];
485
486
        return true;
487
    }
488
}
489