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: * Array of values currently stored in Configure.
37: *
38: * @var array
39: */
40: protected static $_values = [
41: 'debug' => false
42: ];
43:
44: /**
45: * Configured engine classes, used to load config files from resources
46: *
47: * @see \Cake\Core\Configure::load()
48: * @var \Cake\Core\Configure\ConfigEngineInterface[]
49: */
50: protected static $_engines = [];
51:
52: /**
53: * Flag to track whether or not ini_set exists.
54: *
55: * @var bool|null
56: */
57: protected static $_hasIniSet;
58:
59: /**
60: * Used to store a dynamic variable in Configure.
61: *
62: * Usage:
63: * ```
64: * Configure::write('One.key1', 'value of the Configure::One[key1]');
65: * Configure::write(['One.key1' => 'value of the Configure::One[key1]']);
66: * Configure::write('One', [
67: * 'key1' => 'value of the Configure::One[key1]',
68: * 'key2' => 'value of the Configure::One[key2]'
69: * ]);
70: *
71: * Configure::write([
72: * 'One.key1' => 'value of the Configure::One[key1]',
73: * 'One.key2' => 'value of the Configure::One[key2]'
74: * ]);
75: * ```
76: *
77: * @param string|array $config The key to write, can be a dot notation value.
78: * Alternatively can be an array containing key(s) and value(s).
79: * @param mixed $value Value to set for var
80: * @return bool True if write was successful
81: * @link https://book.cakephp.org/3.0/en/development/configuration.html#writing-configuration-data
82: */
83: public static function write($config, $value = null)
84: {
85: if (!is_array($config)) {
86: $config = [$config => $value];
87: }
88:
89: foreach ($config as $name => $value) {
90: static::$_values = Hash::insert(static::$_values, $name, $value);
91: }
92:
93: if (isset($config['debug'])) {
94: if (static::$_hasIniSet === null) {
95: static::$_hasIniSet = function_exists('ini_set');
96: }
97: if (static::$_hasIniSet) {
98: ini_set('display_errors', $config['debug'] ? '1' : '0');
99: }
100: }
101:
102: return true;
103: }
104:
105: /**
106: * Used to read information stored in Configure. It's not
107: * possible to store `null` values in Configure.
108: *
109: * Usage:
110: * ```
111: * Configure::read('Name'); will return all values for Name
112: * Configure::read('Name.key'); will return only the value of Configure::Name[key]
113: * ```
114: *
115: * @param string|null $var Variable to obtain. Use '.' to access array elements.
116: * @param mixed $default The return value when the configure does not exist
117: * @return mixed Value stored in configure, or null.
118: * @link https://book.cakephp.org/3.0/en/development/configuration.html#reading-configuration-data
119: */
120: public static function read($var = null, $default = null)
121: {
122: if ($var === null) {
123: return static::$_values;
124: }
125:
126: return Hash::get(static::$_values, $var, $default);
127: }
128:
129: /**
130: * Returns true if given variable is set in Configure.
131: *
132: * @param string $var Variable name to check for
133: * @return bool True if variable is there
134: */
135: public static function check($var)
136: {
137: if (empty($var)) {
138: return false;
139: }
140:
141: return static::read($var) !== null;
142: }
143:
144: /**
145: * Used to get information stored in Configure. It's not
146: * possible to store `null` values in Configure.
147: *
148: * Acts as a wrapper around Configure::read() and Configure::check().
149: * The configure key/value pair fetched via this method is expected to exist.
150: * In case it does not an exception will be thrown.
151: *
152: * Usage:
153: * ```
154: * Configure::readOrFail('Name'); will return all values for Name
155: * Configure::readOrFail('Name.key'); will return only the value of Configure::Name[key]
156: * ```
157: *
158: * @param string $var Variable to obtain. Use '.' to access array elements.
159: * @return mixed Value stored in configure.
160: * @throws \RuntimeException if the requested configuration is not set.
161: * @link https://book.cakephp.org/3.0/en/development/configuration.html#reading-configuration-data
162: */
163: public static function readOrFail($var)
164: {
165: if (static::check($var) === false) {
166: throw new RuntimeException(sprintf('Expected configuration key "%s" not found.', $var));
167: }
168:
169: return static::read($var);
170: }
171:
172: /**
173: * Used to delete a variable from Configure.
174: *
175: * Usage:
176: * ```
177: * Configure::delete('Name'); will delete the entire Configure::Name
178: * Configure::delete('Name.key'); will delete only the Configure::Name[key]
179: * ```
180: *
181: * @param string $var the var to be deleted
182: * @return void
183: * @link https://book.cakephp.org/3.0/en/development/configuration.html#deleting-configuration-data
184: */
185: public static function delete($var)
186: {
187: static::$_values = Hash::remove(static::$_values, $var);
188: }
189:
190: /**
191: * Used to consume information stored in Configure. It's not
192: * possible to store `null` values in Configure.
193: *
194: * Acts as a wrapper around Configure::consume() and Configure::check().
195: * The configure key/value pair consumed via this method is expected to exist.
196: * In case it does not an exception will be thrown.
197: *
198: * @param string $var Variable to consume. Use '.' to access array elements.
199: * @return mixed Value stored in configure.
200: * @throws \RuntimeException if the requested configuration is not set.
201: * @since 3.6.0
202: */
203: public static function consumeOrFail($var)
204: {
205: if (static::check($var) === false) {
206: throw new RuntimeException(sprintf('Expected configuration key "%s" not found.', $var));
207: }
208:
209: return static::consume($var);
210: }
211:
212: /**
213: * Used to read and delete a variable from Configure.
214: *
215: * This is primarily used during bootstrapping to move configuration data
216: * out of configure into the various other classes in CakePHP.
217: *
218: * @param string $var The key to read and remove.
219: * @return array|string|null
220: */
221: public static function consume($var)
222: {
223: if (strpos($var, '.') === false) {
224: if (!isset(static::$_values[$var])) {
225: return null;
226: }
227: $value = static::$_values[$var];
228: unset(static::$_values[$var]);
229:
230: return $value;
231: }
232: $value = Hash::get(static::$_values, $var);
233: static::delete($var);
234:
235: return $value;
236: }
237:
238: /**
239: * Add a new engine to Configure. Engines allow you to read configuration
240: * files in various formats/storage locations. CakePHP comes with two built-in engines
241: * PhpConfig and IniConfig. You can also implement your own engine classes in your application.
242: *
243: * To add a new engine to Configure:
244: *
245: * ```
246: * Configure::config('ini', new IniConfig());
247: * ```
248: *
249: * @param string $name The name of the engine being configured. This alias is used later to
250: * read values from a specific engine.
251: * @param \Cake\Core\Configure\ConfigEngineInterface $engine The engine to append.
252: * @return void
253: */
254: public static function config($name, ConfigEngineInterface $engine)
255: {
256: static::$_engines[$name] = $engine;
257: }
258:
259: /**
260: * Gets the names of the configured Engine objects.
261: *
262: * Checking if a specific engine has been configured with this method is deprecated.
263: * Use Configure::isConfigured() instead.
264: *
265: * @param string|null $name Engine name.
266: * @return string[]|bool Array of the configured Engine objects, bool for specific name.
267: */
268: public static function configured($name = null)
269: {
270: if ($name !== null) {
271: deprecationWarning(
272: 'Checking for a named engine with configured() is deprecated. ' .
273: 'Use Configure::isConfigured() instead.'
274: );
275:
276: return isset(static::$_engines[$name]);
277: }
278:
279: return array_keys(static::$_engines);
280: }
281:
282: /**
283: * Returns true if the Engine objects is configured.
284: *
285: * @param string $name Engine name.
286: * @return bool
287: */
288: public static function isConfigured($name)
289: {
290: return isset(static::$_engines[$name]);
291: }
292:
293: /**
294: * Remove a configured engine. This will unset the engine
295: * and make any future attempts to use it cause an Exception.
296: *
297: * @param string $name Name of the engine to drop.
298: * @return bool Success
299: */
300: public static function drop($name)
301: {
302: if (!isset(static::$_engines[$name])) {
303: return false;
304: }
305: unset(static::$_engines[$name]);
306:
307: return true;
308: }
309:
310: /**
311: * Loads stored configuration information from a resource. You can add
312: * config file resource engines with `Configure::config()`.
313: *
314: * Loaded configuration information will be merged with the current
315: * runtime configuration. You can load configuration files from plugins
316: * by preceding the filename with the plugin name.
317: *
318: * `Configure::load('Users.user', 'default')`
319: *
320: * Would load the 'user' config file using the default config engine. You can load
321: * app config files by giving the name of the resource you want loaded.
322: *
323: * ```
324: * Configure::load('setup', 'default');
325: * ```
326: *
327: * If using `default` config and no engine has been configured for it yet,
328: * one will be automatically created using PhpConfig
329: *
330: * @param string $key name of configuration resource to load.
331: * @param string $config Name of the configured engine to use to read the resource identified by $key.
332: * @param bool $merge if config files should be merged instead of simply overridden
333: * @return bool False if file not found, true if load successful.
334: * @link https://book.cakephp.org/3.0/en/development/configuration.html#reading-and-writing-configuration-files
335: */
336: public static function load($key, $config = 'default', $merge = true)
337: {
338: $engine = static::_getEngine($config);
339: if (!$engine) {
340: return false;
341: }
342: $values = $engine->read($key);
343:
344: if ($merge) {
345: $values = Hash::merge(static::$_values, $values);
346: }
347:
348: return static::write($values);
349: }
350:
351: /**
352: * Dump data currently in Configure into $key. The serialization format
353: * is decided by the config engine attached as $config. For example, if the
354: * 'default' adapter is a PhpConfig, the generated file will be a PHP
355: * configuration file loadable by the PhpConfig.
356: *
357: * ### Usage
358: *
359: * Given that the 'default' engine is an instance of PhpConfig.
360: * Save all data in Configure to the file `my_config.php`:
361: *
362: * ```
363: * Configure::dump('my_config', 'default');
364: * ```
365: *
366: * Save only the error handling configuration:
367: *
368: * ```
369: * Configure::dump('error', 'default', ['Error', 'Exception'];
370: * ```
371: *
372: * @param string $key The identifier to create in the config adapter.
373: * This could be a filename or a cache key depending on the adapter being used.
374: * @param string $config The name of the configured adapter to dump data with.
375: * @param string[] $keys The name of the top-level keys you want to dump.
376: * This allows you save only some data stored in Configure.
377: * @return bool Success
378: * @throws \Cake\Core\Exception\Exception if the adapter does not implement a `dump` method.
379: */
380: public static function dump($key, $config = 'default', $keys = [])
381: {
382: $engine = static::_getEngine($config);
383: if (!$engine) {
384: throw new Exception(sprintf('There is no "%s" config engine.', $config));
385: }
386: $values = static::$_values;
387: if (!empty($keys) && is_array($keys)) {
388: $values = array_intersect_key($values, array_flip($keys));
389: }
390:
391: return (bool)$engine->dump($key, $values);
392: }
393:
394: /**
395: * Get the configured engine. Internally used by `Configure::load()` and `Configure::dump()`
396: * Will create new PhpConfig for default if not configured yet.
397: *
398: * @param string $config The name of the configured adapter
399: * @return \Cake\Core\Configure\ConfigEngineInterface|false Engine instance or false
400: */
401: protected static function _getEngine($config)
402: {
403: if (!isset(static::$_engines[$config])) {
404: if ($config !== 'default') {
405: return false;
406: }
407: static::config($config, new PhpConfig());
408: }
409:
410: return static::$_engines[$config];
411: }
412:
413: /**
414: * Used to determine the current version of CakePHP.
415: *
416: * Usage
417: * ```
418: * Configure::version();
419: * ```
420: *
421: * @return string Current version of CakePHP
422: */
423: public static function version()
424: {
425: if (!isset(static::$_values['Cake']['version'])) {
426: $config = require CORE_PATH . 'config/config.php';
427: static::write($config);
428: }
429:
430: return static::$_values['Cake']['version'];
431: }
432:
433: /**
434: * Used to write runtime configuration into Cache. Stored runtime configuration can be
435: * restored using `Configure::restore()`. These methods can be used to enable configuration managers
436: * frontends, or other GUI type interfaces for configuration.
437: *
438: * @param string $name The storage name for the saved configuration.
439: * @param string $cacheConfig The cache configuration to save into. Defaults to 'default'
440: * @param array|null $data Either an array of data to store, or leave empty to store all values.
441: * @return bool Success
442: */
443: public static function store($name, $cacheConfig = 'default', $data = null)
444: {
445: if ($data === null) {
446: $data = static::$_values;
447: }
448: if (!class_exists(Cache::class)) {
449: throw new RuntimeException('You must install cakephp/cache to use Configure::store()');
450: }
451:
452: return Cache::write($name, $data, $cacheConfig);
453: }
454:
455: /**
456: * Restores configuration data stored in the Cache into configure. Restored
457: * values will overwrite existing ones.
458: *
459: * @param string $name Name of the stored config file to load.
460: * @param string $cacheConfig Name of the Cache configuration to read from.
461: * @return bool Success.
462: */
463: public static function restore($name, $cacheConfig = 'default')
464: {
465: if (!class_exists(Cache::class)) {
466: throw new RuntimeException('You must install cakephp/cache to use Configure::restore()');
467: }
468: $values = Cache::read($name, $cacheConfig);
469: if ($values) {
470: return static::write($values);
471: }
472:
473: return false;
474: }
475:
476: /**
477: * Clear all values stored in Configure.
478: *
479: * @return bool success.
480: */
481: public static function clear()
482: {
483: static::$_values = [];
484:
485: return true;
486: }
487: }
488: