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 boolean $boot
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: * @return void
117: */
118: protected static function _appDefaults() {
119: self::write('App', (array)self::read('App') + array(
120: 'base' => false,
121: 'baseUrl' => false,
122: 'dir' => APP_DIR,
123: 'webroot' => WEBROOT_DIR,
124: 'www_root' => WWW_ROOT
125: ));
126: }
127:
128: /**
129: * Used to store a dynamic variable in Configure.
130: *
131: * Usage:
132: * {{{
133: * Configure::write('One.key1', 'value of the Configure::One[key1]');
134: * Configure::write(array('One.key1' => 'value of the Configure::One[key1]'));
135: * Configure::write('One', array(
136: * 'key1' => 'value of the Configure::One[key1]',
137: * 'key2' => 'value of the Configure::One[key2]'
138: * );
139: *
140: * Configure::write(array(
141: * 'One.key1' => 'value of the Configure::One[key1]',
142: * 'One.key2' => 'value of the Configure::One[key2]'
143: * ));
144: * }}}
145: *
146: * @link http://book.cakephp.org/2.0/en/development/configuration.html#Configure::write
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 boolean True if write was successful
151: */
152: public static function write($config, $value = null) {
153: if (!is_array($config)) {
154: $config = array($config => $value);
155: }
156:
157: foreach ($config as $name => $value) {
158: self::$_values = Hash::insert(self::$_values, $name, $value);
159: }
160:
161: if (isset($config['debug']) && function_exists('ini_set')) {
162: if (self::$_values['debug']) {
163: ini_set('display_errors', 1);
164: } else {
165: ini_set('display_errors', 0);
166: }
167: }
168: return true;
169: }
170:
171: /**
172: * Used to read information stored in Configure. It's not
173: * possible to store `null` values in Configure.
174: *
175: * Usage:
176: * {{{
177: * Configure::read('Name'); will return all values for Name
178: * Configure::read('Name.key'); will return only the value of Configure::Name[key]
179: * }}}
180: *
181: * @link http://book.cakephp.org/2.0/en/development/configuration.html#Configure::read
182: * @param string $var Variable to obtain. Use '.' to access array elements.
183: * @return mixed value stored in configure, or null.
184: */
185: public static function read($var = null) {
186: if ($var === null) {
187: return self::$_values;
188: }
189: return Hash::get(self::$_values, $var);
190: }
191:
192: /**
193: * Returns true if given variable is set in Configure.
194: *
195: * @param string $var Variable name to check for
196: * @return boolean True if variable is there
197: */
198: public static function check($var = null) {
199: if (empty($var)) {
200: return false;
201: }
202: return Hash::get(self::$_values, $var) !== null;
203: }
204:
205: /**
206: * Used to delete a variable from Configure.
207: *
208: * Usage:
209: * {{{
210: * Configure::delete('Name'); will delete the entire Configure::Name
211: * Configure::delete('Name.key'); will delete only the Configure::Name[key]
212: * }}}
213: *
214: * @link http://book.cakephp.org/2.0/en/development/configuration.html#Configure::delete
215: * @param string $var the var to be deleted
216: * @return void
217: */
218: public static function delete($var = null) {
219: self::$_values = Hash::remove(self::$_values, $var);
220: }
221:
222: /**
223: * Add a new reader to Configure. Readers allow you to read configuration
224: * files in various formats/storage locations. CakePHP comes with two built-in readers
225: * PhpReader and IniReader. You can also implement your own reader classes in your application.
226: *
227: * To add a new reader to Configure:
228: *
229: * `Configure::config('ini', new IniReader());`
230: *
231: * @param string $name The name of the reader being configured. This alias is used later to
232: * read values from a specific reader.
233: * @param ConfigReaderInterface $reader The reader to append.
234: * @return void
235: */
236: public static function config($name, ConfigReaderInterface $reader) {
237: self::$_readers[$name] = $reader;
238: }
239:
240: /**
241: * Gets the names of the configured reader objects.
242: *
243: * @param string $name
244: * @return array Array of the configured reader objects.
245: */
246: public static function configured($name = null) {
247: if ($name) {
248: return isset(self::$_readers[$name]);
249: }
250: return array_keys(self::$_readers);
251: }
252:
253: /**
254: * Remove a configured reader. This will unset the reader
255: * and make any future attempts to use it cause an Exception.
256: *
257: * @param string $name Name of the reader to drop.
258: * @return boolean Success
259: */
260: public static function drop($name) {
261: if (!isset(self::$_readers[$name])) {
262: return false;
263: }
264: unset(self::$_readers[$name]);
265: return true;
266: }
267:
268: /**
269: * Loads stored configuration information from a resource. You can add
270: * config file resource readers with `Configure::config()`.
271: *
272: * Loaded configuration information will be merged with the current
273: * runtime configuration. You can load configuration files from plugins
274: * by preceding the filename with the plugin name.
275: *
276: * `Configure::load('Users.user', 'default')`
277: *
278: * Would load the 'user' config file using the default config reader. You can load
279: * app config files by giving the name of the resource you want loaded.
280: *
281: * `Configure::load('setup', 'default');`
282: *
283: * If using `default` config and no reader has been configured for it yet,
284: * one will be automatically created using PhpReader
285: *
286: * @link http://book.cakephp.org/2.0/en/development/configuration.html#Configure::load
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 boolean $merge if config files should be merged instead of simply overridden
290: * @return mixed false if file not found, void if load successful.
291: * @throws ConfigureException Will throw any exceptions the reader raises.
292: */
293: public static function load($key, $config = 'default', $merge = true) {
294: $reader = self::_getReader($config);
295: if (!$reader) {
296: return false;
297: }
298: $values = $reader->read($key);
299:
300: if ($merge) {
301: $keys = array_keys($values);
302: foreach ($keys as $key) {
303: if (($c = self::read($key)) && is_array($values[$key]) && is_array($c)) {
304: $values[$key] = Hash::merge($c, $values[$key]);
305: }
306: }
307: }
308:
309: return self::write($values);
310: }
311:
312: /**
313: * Dump data currently in Configure into $key. The serialization format
314: * is decided by the config reader attached as $config. For example, if the
315: * 'default' adapter is a PhpReader, the generated file will be a PHP
316: * configuration file loadable by the PhpReader.
317: *
318: * ## Usage
319: *
320: * Given that the 'default' reader is an instance of PhpReader.
321: * Save all data in Configure to the file `my_config.php`:
322: *
323: * `Configure::dump('my_config.php', 'default');`
324: *
325: * Save only the error handling configuration:
326: *
327: * `Configure::dump('error.php', 'default', array('Error', 'Exception');`
328: *
329: * @param string $key The identifier to create in the config adapter.
330: * This could be a filename or a cache key depending on the adapter being used.
331: * @param string $config The name of the configured adapter to dump data with.
332: * @param array $keys The name of the top-level keys you want to dump.
333: * This allows you save only some data stored in Configure.
334: * @return boolean success
335: * @throws ConfigureException if the adapter does not implement a `dump` method.
336: */
337: public static function dump($key, $config = 'default', $keys = array()) {
338: $reader = self::_getReader($config);
339: if (!$reader) {
340: throw new ConfigureException(__d('cake_dev', 'There is no "%s" adapter.', $config));
341: }
342: if (!method_exists($reader, 'dump')) {
343: throw new ConfigureException(__d('cake_dev', 'The "%s" adapter, does not have a %s method.', $config, 'dump()'));
344: }
345: $values = self::$_values;
346: if (!empty($keys) && is_array($keys)) {
347: $values = array_intersect_key($values, array_flip($keys));
348: }
349: return (bool)$reader->dump($key, $values);
350: }
351:
352: /**
353: * Get the configured reader. Internally used by `Configure::load()` and `Configure::dump()`
354: * Will create new PhpReader for default if not configured yet.
355: *
356: * @param string $config The name of the configured adapter
357: * @return mixed Reader instance or false
358: */
359: protected static function _getReader($config) {
360: if (!isset(self::$_readers[$config])) {
361: if ($config !== 'default') {
362: return false;
363: }
364: App::uses('PhpReader', 'Configure');
365: self::config($config, new PhpReader());
366: }
367: return self::$_readers[$config];
368: }
369:
370: /**
371: * Used to determine the current version of CakePHP.
372: *
373: * Usage `Configure::version();`
374: *
375: * @return string Current version of CakePHP
376: */
377: public static function version() {
378: if (!isset(self::$_values['Cake']['version'])) {
379: require CAKE . 'Config' . DS . 'config.php';
380: self::write($config);
381: }
382: return self::$_values['Cake']['version'];
383: }
384:
385: /**
386: * Used to write runtime configuration into Cache. Stored runtime configuration can be
387: * restored using `Configure::restore()`. These methods can be used to enable configuration managers
388: * frontends, or other GUI type interfaces for configuration.
389: *
390: * @param string $name The storage name for the saved configuration.
391: * @param string $cacheConfig The cache configuration to save into. Defaults to 'default'
392: * @param array $data Either an array of data to store, or leave empty to store all values.
393: * @return boolean Success
394: */
395: public static function store($name, $cacheConfig = 'default', $data = null) {
396: if ($data === null) {
397: $data = self::$_values;
398: }
399: return Cache::write($name, $data, $cacheConfig);
400: }
401:
402: /**
403: * Restores configuration data stored in the Cache into configure. Restored
404: * values will overwrite existing ones.
405: *
406: * @param string $name Name of the stored config file to load.
407: * @param string $cacheConfig Name of the Cache configuration to read from.
408: * @return boolean Success.
409: */
410: public static function restore($name, $cacheConfig = 'default') {
411: $values = Cache::read($name, $cacheConfig);
412: if ($values) {
413: return self::write($values);
414: }
415: return false;
416: }
417:
418: /**
419: * Clear all values stored in Configure.
420: *
421: * @return boolean success.
422: */
423: public static function clear() {
424: self::$_values = array();
425: return true;
426: }
427: /**
428: * Set the error and exception handlers.
429: *
430: * @param array $error The Error handling configuration.
431: * @param array $exception The exception handling configuration.
432: * @return void
433: */
434: protected static function _setErrorHandlers($error, $exception) {
435: $level = -1;
436: if (isset($error['level'])) {
437: error_reporting($error['level']);
438: $level = $error['level'];
439: }
440: if (!empty($error['handler'])) {
441: set_error_handler($error['handler'], $level);
442: }
443: if (!empty($exception['handler'])) {
444: set_exception_handler($exception['handler']);
445: }
446: }
447: }
448: