Subversion-Projekte lars-tiefland.cakephp

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
/* SVN FILE: $Id: configure.php 7945 2008-12-19 02:16:01Z gwoo $ */
3
/**
4
 * Short description for file.
5
 *
6
 * Long description for filec
7
 *
8
 * PHP versions 4 and 5
9
 *
10
 * CakePHP(tm) :  Rapid Development Framework (http://www.cakephp.org)
11
 * Copyright 2005-2008, Cake Software Foundation, Inc. (http://www.cakefoundation.org)
12
 *
13
 * Licensed under The MIT License
14
 * Redistributions of files must retain the above copyright notice.
15
 *
16
 * @filesource
17
 * @copyright     Copyright 2005-2008, Cake Software Foundation, Inc. (http://www.cakefoundation.org)
18
 * @link          http://www.cakefoundation.org/projects/info/cakephp CakePHP(tm) Project
19
 * @package       cake
20
 * @subpackage    cake.cake.libs
21
 * @since         CakePHP(tm) v 1.0.0.2363
22
 * @version       $Revision: 7945 $
23
 * @modifiedby    $LastChangedBy: gwoo $
24
 * @lastmodified  $Date: 2008-12-18 18:16:01 -0800 (Thu, 18 Dec 2008) $
25
 * @license       http://www.opensource.org/licenses/mit-license.php The MIT License
26
 */
27
/**
28
 * Configuration class (singleton). Used for managing runtime configuration information.
29
 *
30
 * @package       cake
31
 * @subpackage    cake.cake.libs
32
 * @link          http://book.cakephp.org/view/42/The-Configuration-Class
33
 */
34
class Configure extends Object {
35
/**
36
 * List of additional path(s) where model files reside.
37
 *
38
 * @var array
39
 * @access public
40
 */
41
	var $modelPaths = array();
42
/**
43
 * List of additional path(s) where behavior files reside.
44
 *
45
 * @var array
46
 * @access public
47
 */
48
	var $behaviorPaths = array();
49
/**
50
 * List of additional path(s) where controller files reside.
51
 *
52
 * @var array
53
 * @access public
54
 */
55
	var $controllerPaths = array();
56
/**
57
 * List of additional path(s) where component files reside.
58
 *
59
 * @var array
60
 * @access public
61
 */
62
	var $componentPaths = array();
63
/**
64
 * List of additional path(s) where view files reside.
65
 *
66
 * @var array
67
 * @access public
68
 */
69
	var $viewPaths = array();
70
/**
71
 * List of additional path(s) where helper files reside.
72
 *
73
 * @var array
74
 * @access public
75
 */
76
	var $helperPaths = array();
77
/**
78
 * List of additional path(s) where plugins reside.
79
 *
80
 * @var array
81
 * @access public
82
 */
83
	var $pluginPaths = array();
84
/**
85
 * List of additional path(s) where vendor packages reside.
86
 *
87
 * @var array
88
 * @access public
89
 */
90
	var $vendorPaths = array();
91
/**
92
 * List of additional path(s) where locale files reside.
93
 *
94
 * @var array
95
 * @access public
96
 */
97
	var $localePaths = array();
98
/**
99
 * List of additional path(s) where console shell files reside.
100
 *
101
 * @var array
102
 * @access public
103
 */
104
	var $shellPaths = array();
105
/**
106
 * Current debug level.
107
 *
108
 * @link          http://book.cakephp.org/view/44/CakePHP-Core-Configuration-Variables
109
 * @var integer
110
 * @access public
111
 */
112
	var $debug = null;
113
/**
114
 * Determines if $__objects cache should be written.
115
 *
116
 * @var boolean
117
 * @access private
118
 */
119
	var $__cache = false;
120
/**
121
 * Holds and key => value array of objects' types.
122
 *
123
 * @var array
124
 * @access private
125
 */
126
	var $__objects = array();
127
/**
128
 * Returns a singleton instance of the Configure class.
129
 *
130
 * @return Configure instance
131
 * @access public
132
 */
133
	function &getInstance($boot = true) {
134
		static $instance = array();
135
		if (!$instance) {
136
			$instance[0] =& new Configure();
137
			$instance[0]->__loadBootstrap($boot);
138
		}
139
		return $instance[0];
140
	}
141
/**
142
 * Returns an index of objects of the given type, with the physical path to each object.
143
 *
144
 * @param string	$type Type of object, i.e. 'model', 'controller', 'helper', or 'plugin'
145
 * @param mixed		$path Optional
146
 * @return Configure instance
147
 * @access public
148
 */
149
	function listObjects($type, $path = null, $cache = true) {
150
		$objects = array();
151
		$extension = false;
152
		$name = $type;
153
 
154
		if ($type === 'file' && !$path) {
155
			return false;
156
		} elseif ($type === 'file') {
157
			$extension = true;
158
			$name = $type . str_replace(DS, '', $path);
159
		}
160
		$_this =& Configure::getInstance();
161
 
162
		if (empty($_this->__objects) && $cache === true) {
163
			$_this->__objects = Cache::read('object_map', '_cake_core_');
164
		}
165
 
166
		if (empty($_this->__objects) || !isset($_this->__objects[$type]) || $cache !== true) {
167
			$types = array(
168
				'model' => array('suffix' => '.php', 'base' => 'AppModel', 'core' => false),
169
				'behavior' => array('suffix' => '.php', 'base' => 'ModelBehavior'),
170
				'controller' => array('suffix' => '_controller.php', 'base' => 'AppController'),
171
				'component' => array('suffix' => '.php', 'base' => null),
172
				'view' => array('suffix' => '.php', 'base' => null),
173
				'helper' => array('suffix' => '.php', 'base' => 'AppHelper'),
174
				'plugin' => array('suffix' => '', 'base' => null),
175
				'vendor' => array('suffix' => '', 'base' => null),
176
				'class' => array('suffix' => '.php', 'base' => null),
177
				'file' => array('suffix' => '.php', 'base' => null)
178
			);
179
 
180
			if (!isset($types[$type])) {
181
				return false;
182
			}
183
			$objects = array();
184
 
185
			if (empty($path)) {
186
				$path = $_this->{$type . 'Paths'};
187
				if (isset($types[$type]['core']) && $types[$type]['core'] === false) {
188
					array_pop($path);
189
				}
190
			}
191
			$items = array();
192
 
193
			foreach ((array)$path as $dir) {
194
				if ($type === 'file' || $type === 'class' || strpos($dir, $type) !== false) {
195
					$items = $_this->__list($dir, $types[$type]['suffix'], $extension);
196
					$objects = array_merge($items, array_diff($objects, $items));
197
				}
198
			}
199
 
200
			if ($type !== 'file') {
201
				foreach ($objects as $key => $value) {
202
					$objects[$key] = Inflector::camelize($value);
203
				}
204
			}
205
			if ($cache === true && !empty($objects)) {
206
				$_this->__objects[$name] = $objects;
207
				$_this->__cache = true;
208
			} else {
209
				return $objects;
210
			}
211
		}
212
		return $_this->__objects[$name];
213
	}
214
/**
215
 * Returns an array of filenames of PHP files in the given directory.
216
 *
217
 * @param  string $path Path to scan for files
218
 * @param  string $suffix if false, return only directories. if string, match and return files
219
 * @return array  List of directories or files in directory
220
 */
221
	function __list($path, $suffix = false, $extension = false) {
222
		if (!class_exists('Folder')) {
223
			require LIBS . 'folder.php';
224
		}
225
		$items = array();
226
		$Folder =& new Folder($path);
227
		$contents = $Folder->read(false, true);
228
 
229
		if (is_array($contents)) {
230
			if (!$suffix) {
231
				return $contents[0];
232
			} else {
233
				foreach ($contents[1] as $item) {
234
					if (substr($item, - strlen($suffix)) === $suffix) {
235
						if ($extension) {
236
							$items[] = $item;
237
						} else {
238
							$items[] = substr($item, 0, strlen($item) - strlen($suffix));
239
						}
240
					}
241
				}
242
			}
243
		}
244
		return $items;
245
	}
246
/**
247
 * Used to store a dynamic variable in the Configure instance.
248
 *
249
 * Usage
250
 * Configure::write('One.key1', 'value of the Configure::One[key1]');
251
 * Configure::write(array('One.key1' => 'value of the Configure::One[key1]'));
252
 * Configure::write('One', array(
253
 *     'key1' => 'value of the Configure::One[key1]',
254
 *     'key2' => 'value of the Configure::One[key2]'
255
 * );
256
 * Configure::write(array(
257
 *     'One.key1' => 'value of the Configure::One[key1]',
258
 *     'One.key2' => 'value of the Configure::One[key2]'
259
 * ));
260
 *
261
 * @link          http://book.cakephp.org/view/412/write
262
 * @param array $config Name of var to write
263
 * @param mixed $value Value to set for var
264
 * @return void
265
 * @access public
266
 */
267
	function write($config, $value = null) {
268
		$_this =& Configure::getInstance();
269
 
270
		if (!is_array($config)) {
271
			$config = array($config => $value);
272
		}
273
 
274
		foreach ($config as $names => $value) {
275
			$name = $_this->__configVarNames($names);
276
 
277
			switch (count($name)) {
278
				case 3:
279
					$_this->{$name[0]}[$name[1]][$name[2]] = $value;
280
				break;
281
				case 2:
282
					$_this->{$name[0]}[$name[1]] = $value;
283
				break;
284
				case 1:
285
					$_this->{$name[0]} = $value;
286
				break;
287
			}
288
		}
289
 
290
		if (isset($config['debug'])) {
291
			if ($_this->debug) {
292
				error_reporting(E_ALL);
293
 
294
				if (function_exists('ini_set')) {
295
					ini_set('display_errors', 1);
296
				}
297
 
298
				if (!class_exists('Debugger')) {
299
					require LIBS . 'debugger.php';
300
				}
301
				if (!class_exists('CakeLog')) {
302
					require LIBS . 'cake_log.php';
303
				}
304
				Configure::write('log', LOG_NOTICE);
305
			} else {
306
				error_reporting(0);
307
				Configure::write('log', LOG_NOTICE);
308
			}
309
		}
310
	}
311
/**
312
 * Used to read information stored in the Configure instance.
313
 *
314
 * Usage
315
 * Configure::read('Name'); will return all values for Name
316
 * Configure::read('Name.key'); will return only the value of Configure::Name[key]
317
 *
318
 * @link          http://book.cakephp.org/view/413/read
319
 * @param string $var Variable to obtain
320
 * @return string value of Configure::$var
321
 * @access public
322
 */
323
	function read($var = 'debug') {
324
		$_this =& Configure::getInstance();
325
 
326
		if ($var === 'debug') {
327
			if (!isset($_this->debug)) {
328
				if (defined('DEBUG')) {
329
					$_this->debug = DEBUG;
330
				} else {
331
					$_this->debug = 0;
332
				}
333
			}
334
			return $_this->debug;
335
		}
336
		$name = $_this->__configVarNames($var);
337
 
338
		switch (count($name)) {
339
			case 3:
340
				if (isset($_this->{$name[0]}[$name[1]][$name[2]])) {
341
					return $_this->{$name[0]}[$name[1]][$name[2]];
342
				}
343
			break;
344
			case 2:
345
				if (isset($_this->{$name[0]}[$name[1]])) {
346
					return $_this->{$name[0]}[$name[1]];
347
				}
348
			break;
349
			case 1:
350
				if (isset($_this->{$name[0]})) {
351
					return $_this->{$name[0]};
352
				}
353
			break;
354
		}
355
		return null;
356
	}
357
/**
358
 * Used to delete a variable from the Configure instance.
359
 *
360
 * Usage:
361
 * Configure::delete('Name'); will delete the entire Configure::Name
362
 * Configure::delete('Name.key'); will delete only the Configure::Name[key]
363
 *
364
 * @link          http://book.cakephp.org/view/414/delete
365
 * @param string $var the var to be deleted
366
 * @return void
367
 * @access public
368
 */
369
	function delete($var = null) {
370
		$_this =& Configure::getInstance();
371
		$name = $_this->__configVarNames($var);
372
 
373
		if (count($name) > 1) {
374
			unset($_this->{$name[0]}[$name[1]]);
375
		} else {
376
			unset($_this->{$name[0]});
377
		}
378
	}
379
/**
380
 * Loads a file from app/config/configure_file.php.
381
 * Config file variables should be formated like:
382
 *  $config['name'] = 'value';
383
 * These will be used to create dynamic Configure vars.
384
 *
385
 * Usage Configure::load('configure_file');
386
 *
387
 * @link          http://book.cakephp.org/view/415/load
388
 * @param string $fileName name of file to load, extension must be .php and only the name
389
 *                         should be used, not the extenstion
390
 * @return mixed false if file not found, void if load successful
391
 * @access public
392
 */
393
	function load($fileName) {
394
		$found = false;
395
 
396
		if (file_exists(CONFIGS . $fileName . '.php')) {
397
			include(CONFIGS . $fileName . '.php');
398
			$found = true;
399
		} elseif (file_exists(CACHE . 'persistent' . DS . $fileName . '.php')) {
400
			include(CACHE . 'persistent' . DS . $fileName . '.php');
401
			$found = true;
402
		} else {
403
			foreach (Configure::corePaths('cake') as $key => $path) {
404
				if (file_exists($path . DS . 'config' . DS . $fileName . '.php')) {
405
					include($path . DS . 'config' . DS . $fileName . '.php');
406
					$found = true;
407
					break;
408
				}
409
			}
410
		}
411
 
412
		if (!$found) {
413
			return false;
414
		}
415
 
416
		if (!isset($config)) {
417
			$error = __("Configure::load() - no variable \$config found in %s.php", true);
418
			trigger_error(sprintf($error, $fileName), E_USER_WARNING);
419
			return false;
420
		}
421
		return Configure::write($config);
422
	}
423
/**
424
 * Used to determine the current version of CakePHP.
425
 *
426
 * Usage Configure::version();
427
 *
428
 * @link          http://book.cakephp.org/view/416/version
429
 * @return string Current version of CakePHP
430
 * @access public
431
 */
432
	function version() {
433
		$_this =& Configure::getInstance();
434
 
435
		if (!isset($_this->Cake['version'])) {
436
			require(CORE_PATH . 'cake' . DS . 'config' . DS . 'config.php');
437
			$_this->write($config);
438
		}
439
		return $_this->Cake['version'];
440
	}
441
/**
442
 * Used to write a config file to disk.
443
 *
444
 * Configure::store('Model', 'class.paths', array('Users' => array(
445
 *      'path' => 'users', 'plugin' => true
446
 * )));
447
 *
448
 * @param string $type Type of config file to write, ex: Models, Controllers, Helpers, Components
449
 * @param string $name file name.
450
 * @param array $data array of values to store.
451
 * @return void
452
 * @access public
453
 */
454
	function store($type, $name, $data = array()) {
455
		$write = true;
456
		$content = '';
457
 
458
		foreach ($data as $key => $value) {
459
			$content .= "\$config['$type']['$key']";
460
 
461
			if (is_array($value)) {
462
				$content .= " = array(";
463
 
464
				foreach ($value as $key1 => $value2) {
465
					$value2 = addslashes($value2);
466
					$content .= "'$key1' => '$value2', ";
467
				}
468
				$content .= ");\n";
469
			} else {
470
				$value = addslashes($value);
471
				$content .= " = '$value';\n";
472
			}
473
		}
474
		if (is_null($type)) {
475
			$write = false;
476
		}
477
		Configure::__writeConfig($content, $name, $write);
478
	}
479
/**
480
 * Returns a key/value list of all paths where core libs are found.
481
 * Passing $type only returns the values for a given value of $key.
482
 *
483
 * @param string $type valid values are: 'model', 'behavior', 'controller', 'component',
484
 *                      'view', 'helper', 'datasource', 'libs', and 'cake'
485
 * @return array numeric keyed array of core lib paths
486
 * @access public
487
 */
488
	function corePaths($type = null) {
489
		$paths = Cache::read('core_paths', '_cake_core_');
490
		if (!$paths) {
491
			$paths = array();
492
			$openBasedir = ini_get('open_basedir');
493
			if ($openBasedir) {
494
				$all = explode(PATH_SEPARATOR, $openBasedir);
495
				$all = array_flip(array_flip((array_merge(array(CAKE_CORE_INCLUDE_PATH), $all))));
496
			} else {
497
				$all = explode(PATH_SEPARATOR, ini_get('include_path'));
498
				$all = array_flip(array_flip((array_merge(array(CAKE_CORE_INCLUDE_PATH), $all))));
499
			}
500
			foreach ($all as $path) {
501
				if ($path !== DS) {
502
					$path = rtrim($path, DS);
503
				}
504
				if (empty($path) || $path === '.') {
505
					continue;
506
				}
507
				$cake = $path .  DS . 'cake' . DS;
508
				$libs = $cake . 'libs' . DS;
509
				if (is_dir($libs)) {
510
					$paths['libs'][] = $libs;
511
					$paths['model'][] = $libs . 'model' . DS;
512
					$paths['behavior'][] = $libs . 'model' . DS . 'behaviors' . DS;
513
					$paths['controller'][] = $libs . 'controller' . DS;
514
					$paths['component'][] = $libs . 'controller' . DS . 'components' . DS;
515
					$paths['view'][] = $libs . 'view' . DS;
516
					$paths['helper'][] = $libs . 'view' . DS . 'helpers' . DS;
517
					$paths['cake'][] = $cake;
518
					$paths['vendor'][] = $path . DS . 'vendors' . DS;
519
					$paths['shell'][] = $cake . 'console' . DS . 'libs' . DS;
520
					break;
521
				}
522
			}
523
			Cache::write('core_paths', array_filter($paths), '_cake_core_');
524
		}
525
		if ($type && isset($paths[$type])) {
526
			return $paths[$type];
527
		}
528
		return $paths;
529
	}
530
/**
531
 * Creates a cached version of a configuration file.
532
 * Appends values passed from Configure::store() to the cached file
533
 *
534
 * @param string $content Content to write on file
535
 * @param string $name Name to use for cache file
536
 * @param boolean $write true if content should be written, false otherwise
537
 * @return void
538
 * @access private
539
 */
540
	function __writeConfig($content, $name, $write = true) {
541
		$file = CACHE . 'persistent' . DS . $name . '.php';
542
 
543
		if (Configure::read() > 0) {
544
			$expires = "+10 seconds";
545
		} else {
546
			$expires = "+999 days";
547
		}
548
		$cache = cache('persistent' . DS . $name . '.php', null, $expires);
549
 
550
		if ($cache === null) {
551
			cache('persistent' . DS . $name . '.php', "<?php\n\$config = array();\n", $expires);
552
		}
553
 
554
		if ($write === true) {
555
			if (!class_exists('File')) {
556
				require LIBS . 'file.php';
557
			}
558
			$fileClass = new File($file);
559
 
560
			if ($fileClass->writable()) {
561
				$fileClass->append($content);
562
			}
563
		}
564
	}
565
/**
566
 * Checks $name for dot notation to create dynamic Configure::$var as an array when needed.
567
 *
568
 * @param mixed $name Name to split
569
 * @return array Name separated in items through dot notation
570
 * @access private
571
 */
572
	function __configVarNames($name) {
573
		if (is_string($name)) {
574
			if (strpos($name, ".")) {
575
				return explode(".", $name);
576
			}
577
			return array($name);
578
		}
579
		return $name;
580
	}
581
/**
582
 * Build path references. Merges the supplied $paths
583
 * with the base paths and the default core paths.
584
 *
585
 * @param array $paths paths defines in config/bootstrap.php
586
 * @return void
587
 * @access public
588
 */
589
	function buildPaths($paths) {
590
		$_this =& Configure::getInstance();
591
		$core = $_this->corePaths();
592
		$basePaths = array(
593
			'model' => array(MODELS),
594
			'behavior' => array(BEHAVIORS),
595
			'controller' => array(CONTROLLERS),
596
			'component' => array(COMPONENTS),
597
			'view' => array(VIEWS),
598
			'helper' => array(HELPERS),
599
			'plugin' => array(APP . 'plugins' . DS),
600
			'vendor' => array(APP . 'vendors' . DS, VENDORS),
601
			'locale' => array(APP . 'locale' . DS),
602
			'shell' => array(),
603
			'datasource' => array(MODELS . 'datasources')
604
		);
605
 
606
		foreach ($basePaths as $type => $default) {
607
			$pathsVar = $type . 'Paths';
608
			$merge = array();
609
 
610
			if (isset($core[$type])) {
611
				$merge = $core[$type];
612
			}
613
			if ($type === 'model' || $type === 'controller' || $type === 'helper') {
614
				$merge = array_merge(array(APP), $merge);
615
			}
616
 
617
			if (!is_array($default)) {
618
				$default = array($default);
619
			}
620
			$_this->{$pathsVar} = $default;
621
 
622
			if (isset($paths[$pathsVar]) && !empty($paths[$pathsVar])) {
623
				$path = array_flip(array_flip((array_merge(
624
					$_this->{$pathsVar}, (array)$paths[$pathsVar], $merge
625
				))));
626
				$_this->{$pathsVar} = array_values($path);
627
			} else {
628
				$path = array_flip(array_flip((array_merge($_this->{$pathsVar}, $merge))));
629
				$_this->{$pathsVar} = array_values($path);
630
			}
631
		}
632
	}
633
/**
634
 * Loads app/config/bootstrap.php.
635
 * If the alternative paths are set in this file
636
 * they will be added to the paths vars.
637
 *
638
 * @param boolean $boot Load application bootstrap (if true)
639
 * @return void
640
 * @access private
641
 */
642
	function __loadBootstrap($boot) {
643
		$modelPaths = $behaviorPaths = $controllerPaths = $componentPaths = $viewPaths = $helperPaths = $pluginPaths = $vendorPaths = $localePaths = $shellPaths = null;
644
 
645
		if ($boot) {
646
			Configure::write('App', array('base' => false, 'baseUrl' => false, 'dir' => APP_DIR, 'webroot' => WEBROOT_DIR));
647
 
648
			if (!include(CONFIGS . 'core.php')) {
649
				trigger_error(sprintf(__("Can't find application core file. Please create %score.php, and make sure it is readable by PHP.", true), CONFIGS), E_USER_ERROR);
650
			}
651
 
652
			if (!include(CONFIGS . 'bootstrap.php')) {
653
				trigger_error(sprintf(__("Can't find application bootstrap file. Please create %sbootstrap.php, and make sure it is readable by PHP.", true), CONFIGS), E_USER_ERROR);
654
			}
655
 
656
			if (Configure::read('Cache.disable') !== true) {
657
				$cache = Cache::config('default');
658
 
659
				if (empty($cache['settings'])) {
660
					trigger_error('Cache not configured properly. Please check Cache::config(); in APP/config/core.php', E_USER_WARNING);
661
					$cache = Cache::config('default', array('engine' => 'File'));
662
				}
663
				$path = $prefix = $duration = null;
664
 
665
				if (!empty($cache['settings']['path'])) {
666
					$path = realpath($cache['settings']['path']);
667
				} else {
668
					$prefix = $cache['settings']['prefix'];
669
				}
670
 
671
				if (Configure::read() >= 1) {
672
					$duration = '+10 seconds';
673
				} else {
674
					$duration = '+999 days';
675
				}
676
 
677
				if (Cache::config('_cake_core_') === false) {
678
					Cache::config('_cake_core_', array_merge($cache['settings'], array(
679
						'prefix' => $prefix . 'cake_core_', 'path' => $path . DS . 'persistent' . DS,
680
						'serialize' => true, 'duration' => $duration
681
					)));
682
				}
683
 
684
				if (Cache::config('_cake_model_') === false) {
685
					Cache::config('_cake_model_', array_merge($cache['settings'], array(
686
						'prefix' => $prefix . 'cake_model_', 'path' => $path . DS . 'models' . DS,
687
						'serialize' => true, 'duration' => $duration
688
					)));
689
				}
690
				Cache::config('default');
691
			}
692
			Configure::buildPaths(compact(
693
				'modelPaths', 'viewPaths', 'controllerPaths', 'helperPaths', 'componentPaths',
694
				'behaviorPaths', 'pluginPaths', 'vendorPaths', 'localePaths', 'shellPaths'
695
			));
696
		}
697
	}
698
/**
699
 * Caches the object map when the instance of the Configure class is destroyed
700
 *
701
 * @access public
702
 */
703
	function __destruct() {
704
		if ($this->__cache) {
705
			Cache::write('object_map', array_filter($this->__objects), '_cake_core_');
706
		}
707
	}
708
}
709
/**
710
 * Class and file loader.
711
 *
712
 * @link          http://book.cakephp.org/view/499/The-App-Class
713
 * @since         CakePHP(tm) v 1.2.0.6001
714
 * @package       cake
715
 * @subpackage    cake.cake.libs
716
 */
717
class App extends Object {
718
/**
719
 * Paths to search for files.
720
 *
721
 * @var array
722
 * @access public
723
 */
724
	var $search = array();
725
/**
726
 * Whether or not to return the file that is loaded.
727
 *
728
 * @var boolean
729
 * @access public
730
 */
731
	var $return = false;
732
/**
733
 * Determines if $__maps and $__paths cache should be written.
734
 *
735
 * @var boolean
736
 * @access private
737
 */
738
	var $__cache = false;
739
/**
740
 * Holds key/value pairs of $type => file path.
741
 *
742
 * @var array
743
 * @access private
744
 */
745
	var $__map = array();
746
/**
747
 * Holds paths for deep searching of files.
748
 *
749
 * @var array
750
 * @access private
751
 */
752
	var $__paths = array();
753
/**
754
 * Holds loaded files.
755
 *
756
 * @var array
757
 * @access private
758
 */
759
	var $__loaded = array();
760
/**
761
 * Finds classes based on $name or specific file(s) to search.
762
 *
763
 * @link          http://book.cakephp.org/view/529/Using-App-import
764
 * @param mixed $type The type of Class if passed as a string, or all params can be passed as
765
 *                    an single array to $type,
766
 * @param string $name Name of the Class or a unique name for the file
767
 * @param mixed $parent boolean true if Class Parent should be searched, accepts key => value
768
 *              array('parent' => $parent ,'file' => $file, 'search' => $search, 'ext' => '$ext');
769
 *              $ext allows setting the extension of the file name
770
 *              based on Inflector::underscore($name) . ".$ext";
771
 * @param array $search paths to search for files, array('path 1', 'path 2', 'path 3');
772
 * @param string $file full name of the file to search for including extension
773
 * @param boolean $return, return the loaded file, the file must have a return
774
 *                         statement in it to work: return $variable;
775
 * @return boolean true if Class is already in memory or if file is found and loaded, false if not
776
 * @access public
777
 */
778
	function import($type = null, $name = null, $parent = true, $search = array(), $file = null, $return = false) {
779
		$plugin = $directory = null;
780
 
781
		if (is_array($type)) {
782
			extract($type, EXTR_OVERWRITE);
783
		}
784
 
785
		if (is_array($parent)) {
786
			extract($parent, EXTR_OVERWRITE);
787
		}
788
 
789
		if ($name === null && $file === null) {
790
			$name = $type;
791
			$type = 'Core';
792
		} elseif ($name === null) {
793
			$type = 'File';
794
		}
795
 
796
		if (is_array($name)) {
797
			foreach ($name as $class) {
798
				$tempType = $type;
799
				$plugin = null;
800
 
801
				if (strpos($class, '.') !== false) {
802
					$value = explode('.', $class);
803
					$count = count($value);
804
 
805
					if ($count > 2) {
806
						$tempType = $value[0];
807
						$plugin = $value[1] . '.';
808
						$class = $value[2];
809
					} elseif ($count === 2 && ($type === 'Core' || $type === 'File')) {
810
						$tempType = $value[0];
811
						$class = $value[1];
812
					} else {
813
						$plugin = $value[0] . '.';
814
						$class = $value[1];
815
					}
816
				}
817
 
818
				if (!App::import($tempType, $plugin . $class)) {
819
					return false;
820
				}
821
			}
822
			return true;
823
		}
824
 
825
		if ($name != null && strpos($name, '.') !== false) {
826
			list($plugin, $name) = explode('.', $name);
827
		}
828
		$_this =& App::getInstance();
829
		$_this->return = $return;
830
 
831
		if (isset($ext)) {
832
			$file = Inflector::underscore($name) . ".$ext";
833
		}
834
		$ext = $_this->__settings($type, $plugin, $parent);
835
 
836
		if ($name != null && !class_exists($name . $ext['class'])) {
837
			if ($load = $_this->__mapped($name . $ext['class'], $type, $plugin)) {
838
				if ($_this->__load($load)) {
839
					$_this->__overload($type, $name . $ext['class']);
840
 
841
					if ($_this->return) {
842
						$value = include $load;
843
						return $value;
844
					}
845
					return true;
846
				} else {
847
					$_this->__remove($name . $ext['class'], $type, $plugin);
848
					$_this->__cache = true;
849
				}
850
			}
851
			if (!empty($search)) {
852
				$_this->search = $search;
853
			} elseif ($plugin) {
854
				$_this->search = $_this->__paths('plugin');
855
			} else {
856
				$_this->search = $_this->__paths($type);
857
			}
858
			$find = $file;
859
 
860
			if ($find === null) {
861
				$find = Inflector::underscore($name . $ext['suffix']).'.php';
862
 
863
				if ($plugin) {
864
					$paths = $_this->search;
865
					foreach ($paths as $key => $value) {
866
						$_this->search[$key] = $value . $ext['path'];
867
					}
868
					$plugin = Inflector::camelize($plugin);
869
				}
870
			}
871
 
872
			if (strtolower($type) !== 'vendor' && empty($search) && $_this->__load($file)) {
873
				$directory = false;
874
			} else {
875
				$file = $find;
876
				$directory = $_this->__find($find, true);
877
			}
878
 
879
			if ($directory !== null) {
880
				$_this->__cache = true;
881
				$_this->__map($directory . $file, $name . $ext['class'], $type, $plugin);
882
				$_this->__overload($type, $name . $ext['class']);
883
 
884
				if ($_this->return) {
885
					$value = include $directory . $file;
886
					return $value;
887
				}
888
				return true;
889
			}
890
			return false;
891
		}
892
		return true;
893
	}
894
/**
895
 * Returns a single instance of App.
896
 *
897
 * @return object
898
 * @access public
899
 */
900
	function &getInstance() {
901
		static $instance = array();
902
		if (!$instance) {
903
			$instance[0] =& new App();
904
			$instance[0]->__map = Cache::read('file_map', '_cake_core_');
905
		}
906
		return $instance[0];
907
	}
908
/**
909
 * Locates the $file in $__paths, searches recursively.
910
 *
911
 * @param string $file full file name
912
 * @param boolean $recursive search $__paths recursively
913
 * @return mixed boolean on fail, $file directory path on success
914
 * @access private
915
 */
916
	function __find($file, $recursive = true) {
917
		if (empty($this->search)) {
918
			return null;
919
		} elseif (is_string($this->search)) {
920
			$this->search = array($this->search);
921
		}
922
 
923
		if (empty($this->__paths)) {
924
			$this->__paths = Cache::read('dir_map', '_cake_core_');
925
		}
926
 
927
		foreach ($this->search as $path) {
928
			$path = rtrim($path, DS);
929
 
930
			if ($path === rtrim(APP, DS)) {
931
				$recursive = false;
932
			}
933
			if ($recursive === false) {
934
				if ($this->__load($path . DS . $file)) {
935
					return $path . DS;
936
				}
937
				continue;
938
			}
939
			if (!isset($this->__paths[$path])) {
940
				if (!class_exists('Folder')) {
941
					require LIBS . 'folder.php';
942
				}
943
				$Folder =& new Folder();
944
				$directories = $Folder->tree($path, false, 'dir');
945
				$this->__paths[$path] = $directories;
946
			}
947
 
948
			foreach ($this->__paths[$path] as $directory) {
949
				if ($this->__load($directory . DS . $file)) {
950
					return $directory . DS;
951
				}
952
			}
953
		}
954
		return null;
955
	}
956
/**
957
 * Attempts to load $file.
958
 *
959
 * @param string $file full path to file including file name
960
 * @return boolean
961
 * @access private
962
 */
963
	function __load($file) {
964
		if (empty($file)) {
965
			return false;
966
		}
967
		if (!$this->return && isset($this->__loaded[$file])) {
968
			return true;
969
		}
970
		if (file_exists($file)) {
971
			if (!$this->return) {
972
				require($file);
973
				$this->__loaded[$file] = true;
974
			}
975
			return true;
976
		}
977
		return false;
978
	}
979
/**
980
 * Maps the $name to the $file.
981
 *
982
 * @param string $file full path to file
983
 * @param string $name unique name for this map
984
 * @param string $type type object being mapped
985
 * @param string $plugin if object is from a plugin, the name of the plugin
986
 * @access private
987
 */
988
	function __map($file, $name, $type, $plugin) {
989
		if ($plugin) {
990
			$plugin = Inflector::camelize($plugin);
991
			$this->__map['Plugin'][$plugin][$type][$name] = $file;
992
		} else {
993
			$this->__map[$type][$name] = $file;
994
		}
995
	}
996
/**
997
 * Returns a file's complete path.
998
 *
999
 * @param string $name unique name
1000
 * @param string $type type object
1001
 * @param string $plugin if object is from a plugin, the name of the plugin
1002
 * @return mixed, file path if found, false otherwise
1003
 * @access private
1004
 */
1005
	function __mapped($name, $type, $plugin) {
1006
		if ($plugin) {
1007
			$plugin = Inflector::camelize($plugin);
1008
 
1009
			if (isset($this->__map['Plugin'][$plugin][$type]) && isset($this->__map['Plugin'][$plugin][$type][$name])) {
1010
				return $this->__map['Plugin'][$plugin][$type][$name];
1011
			}
1012
			return false;
1013
		}
1014
 
1015
		if (isset($this->__map[$type]) && isset($this->__map[$type][$name])) {
1016
			return $this->__map[$type][$name];
1017
		}
1018
		return false;
1019
	}
1020
/**
1021
 * Used to overload objects as needed.
1022
 *
1023
 * @param string $type Model or Helper
1024
 * @param string $name Class name to overload
1025
 * @access private
1026
 */
1027
	function __overload($type, $name) {
1028
		if (($type === 'Model' || $type === 'Helper') && strtolower($name) != 'schema') {
1029
			Overloadable::overload($name);
1030
		}
1031
	}
1032
/**
1033
 * Loads parent classes based on $type.
1034
 * Returns a prefix or suffix needed for loading files.
1035
 *
1036
 * @param string $type type of object
1037
 * @param string $plugin name of plugin
1038
 * @param boolean $parent false will not attempt to load parent
1039
 * @return array
1040
 * @access private
1041
 */
1042
	function __settings($type, $plugin, $parent) {
1043
		if (!$parent) {
1044
			return null;
1045
		}
1046
 
1047
		if ($plugin) {
1048
			$plugin = Inflector::underscore($plugin);
1049
			$name = Inflector::camelize($plugin);
1050
		}
1051
		$path = null;
1052
		$load = strtolower($type);
1053
 
1054
		switch ($load) {
1055
			case 'model':
1056
				if (!class_exists('Model')) {
1057
					App::import('Core', 'Model', false, Configure::corePaths('model'));
1058
				}
1059
				if (!class_exists('AppModel')) {
1060
					App::import($type, 'AppModel', false, Configure::read('modelPaths'));
1061
				}
1062
				if ($plugin) {
1063
					if (!class_exists($name . 'AppModel')) {
1064
						App::import($type, $plugin . '.' . $name . 'AppModel', false, array(), $plugin . DS . $plugin . '_app_model.php');
1065
					}
1066
					$path = $plugin . DS . 'models' . DS;
1067
				}
1068
				return array('class' => null, 'suffix' => null, 'path' => $path);
1069
			break;
1070
			case 'behavior':
1071
				if ($plugin) {
1072
					$path = $plugin . DS . 'models' . DS . 'behaviors' . DS;
1073
				}
1074
				return array('class' => $type, 'suffix' => null, 'path' => $path);
1075
			break;
1076
			case 'controller':
1077
				App::import($type, 'AppController', false);
1078
				if ($plugin) {
1079
					App::import($type, $plugin . '.' . $name . 'AppController', false, array(), $plugin . DS . $plugin . '_app_controller.php');
1080
					$path = $plugin . DS . 'controllers' . DS;
1081
				}
1082
				return array('class' => $type, 'suffix' => $type, 'path' => $path);
1083
			break;
1084
			case 'component':
1085
				if ($plugin) {
1086
					$path = $plugin . DS . 'controllers' . DS . 'components' . DS;
1087
				}
1088
				return array('class' => $type, 'suffix' => null, 'path' => $path);
1089
			break;
1090
			case 'view':
1091
				if ($plugin) {
1092
					$path = $plugin . DS . 'views' . DS;
1093
				}
1094
				return array('class' => $type, 'suffix' => null, 'path' => $path);
1095
			break;
1096
			case 'helper':
1097
				if (!class_exists('AppHelper')) {
1098
					App::import($type, 'AppHelper', false);
1099
				}
1100
				if ($plugin) {
1101
					$path = $plugin . DS . 'views' . DS . 'helpers' . DS;
1102
				}
1103
				return array('class' => $type, 'suffix' => null, 'path' => $path);
1104
			break;
1105
			case 'vendor':
1106
				if ($plugin) {
1107
					$path = $plugin . DS . 'vendors' . DS;
1108
				}
1109
				return array('class' => null, 'suffix' => null, 'path' => $path);
1110
			break;
1111
			default:
1112
				$type = $suffix = $path = null;
1113
			break;
1114
		}
1115
		return array('class' => null, 'suffix' => null, 'path' => null);
1116
	}
1117
/**
1118
 * Returns default search paths.
1119
 *
1120
 * @param string $type type of object to be searched
1121
 * @return array list of paths
1122
 * @access private
1123
 */
1124
	function __paths($type) {
1125
		$type = strtolower($type);
1126
 
1127
		if ($type === 'core') {
1128
			$path = Configure::corePaths();
1129
			$paths = array();
1130
 
1131
			foreach ($path as $key => $value) {
1132
				$count = count($key);
1133
				for ($i = 0; $i < $count; $i++) {
1134
					$paths[] = $path[$key][$i];
1135
				}
1136
			}
1137
			return $paths;
1138
		}
1139
 
1140
		if ($paths = Configure::read($type . 'Paths')) {
1141
			return $paths;
1142
		}
1143
 
1144
		switch ($type) {
1145
			case 'plugin':
1146
				return array(APP . 'plugins' . DS);
1147
			case 'vendor':
1148
				return array(APP . 'vendors' . DS, VENDORS, APP . 'plugins' . DS);
1149
			case 'controller':
1150
				return array(APP . 'controllers' . DS, APP);
1151
			case 'model':
1152
				return array(APP . 'models' . DS, APP);
1153
			case 'view':
1154
				return array(APP . 'views' . DS);
1155
		}
1156
	}
1157
/**
1158
 * Removes file location from map if the file has been deleted.
1159
 *
1160
 * @param string $name name of object
1161
 * @param string $type type of object
1162
 * @param string $plugin name of plugin
1163
 * @return void
1164
 * @access private
1165
 */
1166
	function __remove($name, $type, $plugin) {
1167
		if ($plugin) {
1168
			$plugin = Inflector::camelize($plugin);
1169
			unset($this->__map['Plugin'][$plugin][$type][$name]);
1170
		} else {
1171
			unset($this->__map[$type][$name]);
1172
		}
1173
	}
1174
/**
1175
 * Object destructor.
1176
 *
1177
 * Writes cache file if changes have been made to the $__map or $__paths
1178
 *
1179
 * @return void
1180
 * @access private
1181
 */
1182
	function __destruct() {
1183
		if ($this->__cache) {
1184
			$core = Configure::corePaths('cake');
1185
			unset($this->__paths[rtrim($core[0], DS)]);
1186
			Cache::write('dir_map', array_filter($this->__paths), '_cake_core_');
1187
			Cache::write('file_map', array_filter($this->__map), '_cake_core_');
1188
		}
1189
	}
1190
}
1191
?>