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