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