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