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);
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: 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);
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: 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 string[]|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: 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: 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: