1: <?php
2: /**
3: * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
4: * Copyright (c) Cake Software Foundation, Inc. (http://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. (http://cakefoundation.org)
11: * @link http://cakephp.org CakePHP(tm) Project
12: * @package Cake.Core
13: * @since CakePHP(tm) v 1.0.0.2363
14: * @license http://www.opensource.org/licenses/mit-license.php MIT License
15: */
16:
17: App::uses('Hash', 'Utility');
18: App::uses('ConfigReaderInterface', 'Configure');
19:
20: /**
21: * Compatibility with 2.1, which expects Configure to load Set.
22: */
23: App::uses('Set', 'Utility');
24:
25: /**
26: * Configuration class. Used for managing runtime configuration information.
27: *
28: * Provides features for reading and writing to the runtime configuration, as well
29: * as methods for loading additional configuration files or storing runtime configuration
30: * for future use.
31: *
32: * @package Cake.Core
33: * @link http://book.cakephp.org/2.0/en/development/configuration.html#configure-class
34: */
35: class Configure {
36:
37: /**
38: * Array of values currently stored in Configure.
39: *
40: * @var array
41: */
42: protected static $_values = array(
43: 'debug' => 0
44: );
45:
46: /**
47: * Configured reader classes, used to load config files from resources
48: *
49: * @var array
50: * @see Configure::load()
51: */
52: protected static $_readers = array();
53:
54: /**
55: * Initializes configure and runs the bootstrap process.
56: * Bootstrapping includes the following steps:
57: *
58: * - Setup App array in Configure.
59: * - Include app/Config/core.php.
60: * - Configure core cache configurations.
61: * - Load App cache files.
62: * - Include app/Config/bootstrap.php.
63: * - Setup error/exception handlers.
64: *
65: * @param bool $boot Whether to do bootstrapping.
66: * @return void
67: */
68: public static function bootstrap($boot = true) {
69: if ($boot) {
70: self::_appDefaults();
71:
72: if (!include APP . 'Config' . DS . 'core.php') {
73: trigger_error(__d('cake_dev',
74: "Can't find application core file. Please create %s, and make sure it is readable by PHP.",
75: APP . 'Config' . DS . 'core.php'),
76: E_USER_ERROR
77: );
78: }
79: App::init();
80: App::$bootstrapping = false;
81: App::build();
82:
83: $exception = array(
84: 'handler' => 'ErrorHandler::handleException',
85: );
86: $error = array(
87: 'handler' => 'ErrorHandler::handleError',
88: 'level' => E_ALL & ~E_DEPRECATED,
89: );
90: self::_setErrorHandlers($error, $exception);
91:
92: if (!include APP . 'Config' . DS . 'bootstrap.php') {
93: trigger_error(__d('cake_dev',
94: "Can't find application bootstrap file. Please create %s, and make sure it is readable by PHP.",
95: APP . 'Config' . DS . 'bootstrap.php'),
96: E_USER_ERROR
97: );
98: }
99: restore_error_handler();
100:
101: self::_setErrorHandlers(
102: self::$_values['Error'],
103: self::$_values['Exception']
104: );
105:
106: // Preload Debugger + String in case of E_STRICT errors when loading files.
107: if (self::$_values['debug'] > 0) {
108: class_exists('Debugger');
109: class_exists('String');
110: }
111: }
112: }
113:
114: /**
115: * Set app's default configs
116: *
117: * @return void
118: */
119: protected static function _appDefaults() {
120: self::write('App', (array)self::read('App') + array(
121: 'base' => false,
122: 'baseUrl' => false,
123: 'dir' => APP_DIR,
124: 'webroot' => WEBROOT_DIR,
125: 'www_root' => WWW_ROOT
126: ));
127: }
128:
129: /**
130: * Used to store a dynamic variable in Configure.
131: *
132: * Usage:
133: * {{{
134: * Configure::write('One.key1', 'value of the Configure::One[key1]');
135: * Configure::write(array('One.key1' => 'value of the Configure::One[key1]'));
136: * Configure::write('One', array(
137: * 'key1' => 'value of the Configure::One[key1]',
138: * 'key2' => 'value of the Configure::One[key2]'
139: * );
140: *
141: * Configure::write(array(
142: * 'One.key1' => 'value of the Configure::One[key1]',
143: * 'One.key2' => 'value of the Configure::One[key2]'
144: * ));
145: * }}}
146: *
147: * @param string|array $config The key to write, can be a dot notation value.
148: * Alternatively can be an array containing key(s) and value(s).
149: * @param mixed $value Value to set for var
150: * @return bool True if write was successful
151: * @link http://book.cakephp.org/2.0/en/development/configuration.html#Configure::write
152: */
153: public static function write($config, $value = null) {
154: if (!is_array($config)) {
155: $config = array($config => $value);
156: }
157:
158: foreach ($config as $name => $value) {
159: self::$_values = Hash::insert(self::$_values, $name, $value);
160: }
161:
162: if (isset($config['debug']) && function_exists('ini_set')) {
163: if (self::$_values['debug']) {
164: ini_set('display_errors', 1);
165: } else {
166: ini_set('display_errors', 0);
167: }
168: }
169: return true;
170: }
171:
172: /**
173: * Used to read information stored in Configure. It's not
174: * possible to store `null` values in Configure.
175: *
176: * Usage:
177: * {{{
178: * Configure::read('Name'); will return all values for Name
179: * Configure::read('Name.key'); will return only the value of Configure::Name[key]
180: * }}}
181: *
182: * @param string $var Variable to obtain. Use '.' to access array elements.
183: * @return mixed value stored in configure, or null.
184: * @link http://book.cakephp.org/2.0/en/development/configuration.html#Configure::read
185: */
186: public static function read($var = null) {
187: if ($var === null) {
188: return self::$_values;
189: }
190: return Hash::get(self::$_values, $var);
191: }
192:
193: /**
194: * Returns true if given variable is set in Configure.
195: *
196: * @param string $var Variable name to check for
197: * @return bool True if variable is there
198: */
199: public static function check($var = null) {
200: if (empty($var)) {
201: return false;
202: }
203: return Hash::get(self::$_values, $var) !== null;
204: }
205:
206: /**
207: * Used to delete a variable from Configure.
208: *
209: * Usage:
210: * {{{
211: * Configure::delete('Name'); will delete the entire Configure::Name
212: * Configure::delete('Name.key'); will delete only the Configure::Name[key]
213: * }}}
214: *
215: * @param string $var the var to be deleted
216: * @return void
217: * @link http://book.cakephp.org/2.0/en/development/configuration.html#Configure::delete
218: */
219: public static function delete($var = null) {
220: self::$_values = Hash::remove(self::$_values, $var);
221: }
222:
223: /**
224: * Add a new reader to Configure. Readers allow you to read configuration
225: * files in various formats/storage locations. CakePHP comes with two built-in readers
226: * PhpReader and IniReader. You can also implement your own reader classes in your application.
227: *
228: * To add a new reader to Configure:
229: *
230: * `Configure::config('ini', new IniReader());`
231: *
232: * @param string $name The name of the reader being configured. This alias is used later to
233: * read values from a specific reader.
234: * @param ConfigReaderInterface $reader The reader to append.
235: * @return void
236: */
237: public static function config($name, ConfigReaderInterface $reader) {
238: self::$_readers[$name] = $reader;
239: }
240:
241: /**
242: * Gets the names of the configured reader objects.
243: *
244: * @param string $name Name to check. If null returns all configured reader names.
245: * @return array Array of the configured reader objects.
246: */
247: public static function configured($name = null) {
248: if ($name) {
249: return isset(self::$_readers[$name]);
250: }
251: return array_keys(self::$_readers);
252: }
253:
254: /**
255: * Remove a configured reader. This will unset the reader
256: * and make any future attempts to use it cause an Exception.
257: *
258: * @param string $name Name of the reader to drop.
259: * @return bool Success
260: */
261: public static function drop($name) {
262: if (!isset(self::$_readers[$name])) {
263: return false;
264: }
265: unset(self::$_readers[$name]);
266: return true;
267: }
268:
269: /**
270: * Loads stored configuration information from a resource. You can add
271: * config file resource readers with `Configure::config()`.
272: *
273: * Loaded configuration information will be merged with the current
274: * runtime configuration. You can load configuration files from plugins
275: * by preceding the filename with the plugin name.
276: *
277: * `Configure::load('Users.user', 'default')`
278: *
279: * Would load the 'user' config file using the default config reader. You can load
280: * app config files by giving the name of the resource you want loaded.
281: *
282: * `Configure::load('setup', 'default');`
283: *
284: * If using `default` config and no reader has been configured for it yet,
285: * one will be automatically created using PhpReader
286: *
287: * @param string $key name of configuration resource to load.
288: * @param string $config Name of the configured reader to use to read the resource identified by $key.
289: * @param bool $merge if config files should be merged instead of simply overridden
290: * @return bool False if file not found, true if load successful.
291: * @throws ConfigureException Will throw any exceptions the reader raises.
292: * @link http://book.cakephp.org/2.0/en/development/configuration.html#Configure::load
293: */
294: public static function load($key, $config = 'default', $merge = true) {
295: $reader = self::_getReader($config);
296: if (!$reader) {
297: return false;
298: }
299: $values = $reader->read($key);
300:
301: if ($merge) {
302: $keys = array_keys($values);
303: foreach ($keys as $key) {
304: if (($c = self::read($key)) && is_array($values[$key]) && is_array($c)) {
305: $values[$key] = Hash::merge($c, $values[$key]);
306: }
307: }
308: }
309:
310: return self::write($values);
311: }
312:
313: /**
314: * Dump data currently in Configure into $key. The serialization format
315: * is decided by the config reader attached as $config. For example, if the
316: * 'default' adapter is a PhpReader, the generated file will be a PHP
317: * configuration file loadable by the PhpReader.
318: *
319: * ## Usage
320: *
321: * Given that the 'default' reader is an instance of PhpReader.
322: * Save all data in Configure to the file `my_config.php`:
323: *
324: * `Configure::dump('my_config.php', 'default');`
325: *
326: * Save only the error handling configuration:
327: *
328: * `Configure::dump('error.php', 'default', array('Error', 'Exception');`
329: *
330: * @param string $key The identifier to create in the config adapter.
331: * This could be a filename or a cache key depending on the adapter being used.
332: * @param string $config The name of the configured adapter to dump data with.
333: * @param array $keys The name of the top-level keys you want to dump.
334: * This allows you save only some data stored in Configure.
335: * @return bool success
336: * @throws ConfigureException if the adapter does not implement a `dump` method.
337: */
338: public static function dump($key, $config = 'default', $keys = array()) {
339: $reader = self::_getReader($config);
340: if (!$reader) {
341: throw new ConfigureException(__d('cake_dev', 'There is no "%s" adapter.', $config));
342: }
343: if (!method_exists($reader, 'dump')) {
344: throw new ConfigureException(__d('cake_dev', 'The "%s" adapter, does not have a %s method.', $config, 'dump()'));
345: }
346: $values = self::$_values;
347: if (!empty($keys) && is_array($keys)) {
348: $values = array_intersect_key($values, array_flip($keys));
349: }
350: return (bool)$reader->dump($key, $values);
351: }
352:
353: /**
354: * Get the configured reader. Internally used by `Configure::load()` and `Configure::dump()`
355: * Will create new PhpReader for default if not configured yet.
356: *
357: * @param string $config The name of the configured adapter
358: * @return mixed Reader instance or false
359: */
360: protected static function _getReader($config) {
361: if (!isset(self::$_readers[$config])) {
362: if ($config !== 'default') {
363: return false;
364: }
365: App::uses('PhpReader', 'Configure');
366: self::config($config, new PhpReader());
367: }
368: return self::$_readers[$config];
369: }
370:
371: /**
372: * Used to determine the current version of CakePHP.
373: *
374: * Usage `Configure::version();`
375: *
376: * @return string Current version of CakePHP
377: */
378: public static function version() {
379: if (!isset(self::$_values['Cake']['version'])) {
380: require CAKE . 'Config' . DS . 'config.php';
381: self::write($config);
382: }
383: return self::$_values['Cake']['version'];
384: }
385:
386: /**
387: * Used to write runtime configuration into Cache. Stored runtime configuration can be
388: * restored using `Configure::restore()`. These methods can be used to enable configuration managers
389: * frontends, or other GUI type interfaces for configuration.
390: *
391: * @param string $name The storage name for the saved configuration.
392: * @param string $cacheConfig The cache configuration to save into. Defaults to 'default'
393: * @param array $data Either an array of data to store, or leave empty to store all values.
394: * @return bool Success
395: */
396: public static function store($name, $cacheConfig = 'default', $data = null) {
397: if ($data === null) {
398: $data = self::$_values;
399: }
400: return Cache::write($name, $data, $cacheConfig);
401: }
402:
403: /**
404: * Restores configuration data stored in the Cache into configure. Restored
405: * values will overwrite existing ones.
406: *
407: * @param string $name Name of the stored config file to load.
408: * @param string $cacheConfig Name of the Cache configuration to read from.
409: * @return bool Success.
410: */
411: public static function restore($name, $cacheConfig = 'default') {
412: $values = Cache::read($name, $cacheConfig);
413: if ($values) {
414: return self::write($values);
415: }
416: return false;
417: }
418:
419: /**
420: * Clear all values stored in Configure.
421: *
422: * @return bool success.
423: */
424: public static function clear() {
425: self::$_values = array();
426: return true;
427: }
428:
429: /**
430: * Set the error and exception handlers.
431: *
432: * @param array $error The Error handling configuration.
433: * @param array $exception The exception handling configuration.
434: * @return void
435: */
436: protected static function _setErrorHandlers($error, $exception) {
437: $level = -1;
438: if (isset($error['level'])) {
439: error_reporting($error['level']);
440: $level = $error['level'];
441: }
442: if (!empty($error['handler'])) {
443: set_error_handler($error['handler'], $level);
444: }
445: if (!empty($exception['handler'])) {
446: set_exception_handler($exception['handler']);
447: }
448: }
449:
450: }
451: