Subversion Repositories SmartDukaan

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
16591 anikendra 1
<?php
2
/**
3
 * App class
4
 *
5
 * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
6
 * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
7
 *
8
 * Licensed under The MIT License
9
 * For full copyright and license information, please see the LICENSE.txt
10
 * Redistributions of files must retain the above copyright notice.
11
 *
12
 * @copyright     Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
13
 * @link          http://cakephp.org CakePHP(tm) Project
14
 * @package       Cake.Core
15
 * @since         CakePHP(tm) v 1.2.0.6001
16
 * @license       http://www.opensource.org/licenses/mit-license.php MIT License
17
 */
18
 
19
App::uses('Inflector', 'Utility');
20
App::uses('CakePlugin', 'Core');
21
 
22
/**
23
 * App is responsible for path management, class location and class loading.
24
 *
25
 * ### Adding paths
26
 *
27
 * You can add paths to the search indexes App uses to find classes using `App::build()`. Adding
28
 * additional controller paths for example would alter where CakePHP looks for controllers.
29
 * This allows you to split your application up across the filesystem.
30
 *
31
 * ### Packages
32
 *
33
 * CakePHP is organized around the idea of packages, each class belongs to a package or folder where other
34
 * classes reside. You can configure each package location in your application using `App::build('APackage/SubPackage', $paths)`
35
 * to inform the framework where should each class be loaded. Almost every class in the CakePHP framework can be swapped
36
 * by your own compatible implementation. If you wish to use your own class instead of the classes the framework provides,
37
 * just add the class to your libs folder mocking the directory location of where CakePHP expects to find it.
38
 *
39
 * For instance if you'd like to use your own HttpSocket class, put it under
40
 *
41
 *		app/Network/Http/HttpSocket.php
42
 *
43
 * ### Inspecting loaded paths
44
 *
45
 * You can inspect the currently loaded paths using `App::path('Controller')` for example to see loaded
46
 * controller paths.
47
 *
48
 * It is also possible to inspect paths for plugin classes, for instance, to see a plugin's helpers you would call
49
 * `App::path('View/Helper', 'MyPlugin')`
50
 *
51
 * ### Locating plugins and themes
52
 *
53
 * Plugins and Themes can be located with App as well. Using App::pluginPath('DebugKit') for example, will
54
 * give you the full path to the DebugKit plugin. App::themePath('purple'), would give the full path to the
55
 * `purple` theme.
56
 *
57
 * ### Inspecting known objects
58
 *
59
 * You can find out which objects App knows about using App::objects('Controller') for example to find
60
 * which application controllers App knows about.
61
 *
62
 * @link          http://book.cakephp.org/2.0/en/core-utility-libraries/app.html
63
 * @package       Cake.Core
64
 */
65
class App {
66
 
67
/**
68
 * Append paths
69
 *
70
 * @var string
71
 */
72
	const APPEND = 'append';
73
 
74
/**
75
 * Prepend paths
76
 *
77
 * @var string
78
 */
79
	const PREPEND = 'prepend';
80
 
81
/**
82
 * Register package
83
 *
84
 * @var string
85
 */
86
	const REGISTER = 'register';
87
 
88
/**
89
 * Reset paths instead of merging
90
 *
91
 * @var bool
92
 */
93
	const RESET = true;
94
 
95
/**
96
 * List of object types and their properties
97
 *
98
 * @var array
99
 */
100
	public static $types = array(
101
		'class' => array('extends' => null, 'core' => true),
102
		'file' => array('extends' => null, 'core' => true),
103
		'model' => array('extends' => 'AppModel', 'core' => false),
104
		'behavior' => array('suffix' => 'Behavior', 'extends' => 'Model/ModelBehavior', 'core' => true),
105
		'controller' => array('suffix' => 'Controller', 'extends' => 'AppController', 'core' => true),
106
		'component' => array('suffix' => 'Component', 'extends' => null, 'core' => true),
107
		'lib' => array('extends' => null, 'core' => true),
108
		'view' => array('suffix' => 'View', 'extends' => null, 'core' => true),
109
		'helper' => array('suffix' => 'Helper', 'extends' => 'AppHelper', 'core' => true),
110
		'vendor' => array('extends' => null, 'core' => true),
111
		'shell' => array('suffix' => 'Shell', 'extends' => 'AppShell', 'core' => true),
112
		'plugin' => array('extends' => null, 'core' => true)
113
	);
114
 
115
/**
116
 * Paths to search for files.
117
 *
118
 * @var array
119
 */
120
	public static $search = array();
121
 
122
/**
123
 * Whether or not to return the file that is loaded.
124
 *
125
 * @var bool
126
 */
127
	public static $return = false;
128
 
129
/**
130
 * Holds key/value pairs of $type => file path.
131
 *
132
 * @var array
133
 */
134
	protected static $_map = array();
135
 
136
/**
137
 * Holds and key => value array of object types.
138
 *
139
 * @var array
140
 */
141
	protected static $_objects = array();
142
 
143
/**
144
 * Holds the location of each class
145
 *
146
 * @var array
147
 */
148
	protected static $_classMap = array();
149
 
150
/**
151
 * Holds the possible paths for each package name
152
 *
153
 * @var array
154
 */
155
	protected static $_packages = array();
156
 
157
/**
158
 * Holds the templates for each customizable package path in the application
159
 *
160
 * @var array
161
 */
162
	protected static $_packageFormat = array();
163
 
164
/**
165
 * Maps an old style CakePHP class type to the corresponding package
166
 *
167
 * @var array
168
 */
169
	public static $legacy = array(
170
		'models' => 'Model',
171
		'behaviors' => 'Model/Behavior',
172
		'datasources' => 'Model/Datasource',
173
		'controllers' => 'Controller',
174
		'components' => 'Controller/Component',
175
		'views' => 'View',
176
		'helpers' => 'View/Helper',
177
		'shells' => 'Console/Command',
178
		'libs' => 'Lib',
179
		'vendors' => 'Vendor',
180
		'plugins' => 'Plugin',
181
		'locales' => 'Locale'
182
	);
183
 
184
/**
185
 * Indicates whether the class cache should be stored again because of an addition to it
186
 *
187
 * @var bool
188
 */
189
	protected static $_cacheChange = false;
190
 
191
/**
192
 * Indicates whether the object cache should be stored again because of an addition to it
193
 *
194
 * @var bool
195
 */
196
	protected static $_objectCacheChange = false;
197
 
198
/**
199
 * Indicates the the Application is in the bootstrapping process. Used to better cache
200
 * loaded classes while the cache libraries have not been yet initialized
201
 *
202
 * @var bool
203
 */
204
	public static $bootstrapping = false;
205
 
206
/**
207
 * Used to read information stored path
208
 *
209
 * Usage:
210
 *
211
 * `App::path('Model'); will return all paths for models`
212
 *
213
 * `App::path('Model/Datasource', 'MyPlugin'); will return the path for datasources under the 'MyPlugin' plugin`
214
 *
215
 * @param string $type type of path
216
 * @param string $plugin name of plugin
217
 * @return array
218
 * @link http://book.cakephp.org/2.0/en/core-utility-libraries/app.html#App::path
219
 */
220
	public static function path($type, $plugin = null) {
221
		if (!empty(static::$legacy[$type])) {
222
			$type = static::$legacy[$type];
223
		}
224
 
225
		if (!empty($plugin)) {
226
			$path = array();
227
			$pluginPath = CakePlugin::path($plugin);
228
			$packageFormat = static::_packageFormat();
229
			if (!empty($packageFormat[$type])) {
230
				foreach ($packageFormat[$type] as $f) {
231
					$path[] = sprintf($f, $pluginPath);
232
				}
233
			}
234
			return $path;
235
		}
236
 
237
		if (!isset(static::$_packages[$type])) {
238
			return array();
239
		}
240
		return static::$_packages[$type];
241
	}
242
 
243
/**
244
 * Get all the currently loaded paths from App. Useful for inspecting
245
 * or storing all paths App knows about. For a paths to a specific package
246
 * use App::path()
247
 *
248
 * @return array An array of packages and their associated paths.
249
 * @link http://book.cakephp.org/2.0/en/core-utility-libraries/app.html#App::paths
250
 */
251
	public static function paths() {
252
		return static::$_packages;
253
	}
254
 
255
/**
256
 * Sets up each package location on the file system. You can configure multiple search paths
257
 * for each package, those will be used to look for files one folder at a time in the specified order
258
 * All paths should be terminated with a Directory separator
259
 *
260
 * Usage:
261
 *
262
 * `App::build(array('Model' => array('/a/full/path/to/models/'))); will setup a new search path for the Model package`
263
 *
264
 * `App::build(array('Model' => array('/path/to/models/')), App::RESET); will setup the path as the only valid path for searching models`
265
 *
266
 * `App::build(array('View/Helper' => array('/path/to/helpers/', '/another/path/'))); will setup multiple search paths for helpers`
267
 *
268
 * `App::build(array('Service' => array('%s' . 'Service' . DS)), App::REGISTER); will register new package 'Service'`
269
 *
270
 * If reset is set to true, all loaded plugins will be forgotten and they will be needed to be loaded again.
271
 *
272
 * @param array $paths associative array with package names as keys and a list of directories for new search paths
273
 * @param bool|string $mode App::RESET will set paths, App::APPEND with append paths, App::PREPEND will prepend paths (default)
274
 * 	App::REGISTER will register new packages and their paths, %s in path will be replaced by APP path
275
 * @return void
276
 * @link http://book.cakephp.org/2.0/en/core-utility-libraries/app.html#App::build
277
 */
278
	public static function build($paths = array(), $mode = App::PREPEND) {
279
		//Provides Backwards compatibility for old-style package names
280
		$legacyPaths = array();
281
		foreach ($paths as $type => $path) {
282
			if (!empty(static::$legacy[$type])) {
283
				$type = static::$legacy[$type];
284
			}
285
			$legacyPaths[$type] = $path;
286
		}
287
		$paths = $legacyPaths;
288
 
289
		if ($mode === App::RESET) {
290
			foreach ($paths as $type => $new) {
291
				static::$_packages[$type] = (array)$new;
292
				static::objects($type, null, false);
293
			}
294
			return;
295
		}
296
 
297
		if (empty($paths)) {
298
			static::$_packageFormat = null;
299
		}
300
 
301
		$packageFormat = static::_packageFormat();
302
 
303
		if ($mode === App::REGISTER) {
304
			foreach ($paths as $package => $formats) {
305
				if (empty($packageFormat[$package])) {
306
					$packageFormat[$package] = $formats;
307
				} else {
308
					$formats = array_merge($packageFormat[$package], $formats);
309
					$packageFormat[$package] = array_values(array_unique($formats));
310
				}
311
			}
312
			static::$_packageFormat = $packageFormat;
313
		}
314
 
315
		$defaults = array();
316
		foreach ($packageFormat as $package => $format) {
317
			foreach ($format as $f) {
318
				$defaults[$package][] = sprintf($f, APP);
319
			}
320
		}
321
 
322
		if (empty($paths)) {
323
			static::$_packages = $defaults;
324
			return;
325
		}
326
 
327
		if ($mode === App::REGISTER) {
328
			$paths = array();
329
		}
330
 
331
		foreach ($defaults as $type => $default) {
332
			if (!empty(static::$_packages[$type])) {
333
				$path = static::$_packages[$type];
334
			} else {
335
				$path = $default;
336
			}
337
 
338
			if (!empty($paths[$type])) {
339
				$newPath = (array)$paths[$type];
340
 
341
				if ($mode === App::PREPEND) {
342
					$path = array_merge($newPath, $path);
343
				} else {
344
					$path = array_merge($path, $newPath);
345
				}
346
 
347
				$path = array_values(array_unique($path));
348
			}
349
 
350
			static::$_packages[$type] = $path;
351
		}
352
	}
353
 
354
/**
355
 * Gets the path that a plugin is on. Searches through the defined plugin paths.
356
 *
357
 * Usage:
358
 *
359
 * `App::pluginPath('MyPlugin'); will return the full path to 'MyPlugin' plugin'`
360
 *
361
 * @param string $plugin CamelCased/lower_cased plugin name to find the path of.
362
 * @return string full path to the plugin.
363
 * @link http://book.cakephp.org/2.0/en/core-utility-libraries/app.html#App::pluginPath
364
 * @deprecated 3.0.0 Use `CakePlugin::path()` instead.
365
 */
366
	public static function pluginPath($plugin) {
367
		return CakePlugin::path($plugin);
368
	}
369
 
370
/**
371
 * Finds the path that a theme is on. Searches through the defined theme paths.
372
 *
373
 * Usage:
374
 *
375
 * `App::themePath('MyTheme'); will return the full path to the 'MyTheme' theme`
376
 *
377
 * @param string $theme theme name to find the path of.
378
 * @return string full path to the theme.
379
 * @link http://book.cakephp.org/2.0/en/core-utility-libraries/app.html#App::themePath
380
 */
381
	public static function themePath($theme) {
382
		$themeDir = 'Themed' . DS . Inflector::camelize($theme);
383
		foreach (static::$_packages['View'] as $path) {
384
			if (is_dir($path . $themeDir)) {
385
				return $path . $themeDir . DS;
386
			}
387
		}
388
		return static::$_packages['View'][0] . $themeDir . DS;
389
	}
390
 
391
/**
392
 * Returns the full path to a package inside the CakePHP core
393
 *
394
 * Usage:
395
 *
396
 * `App::core('Cache/Engine'); will return the full path to the cache engines package`
397
 *
398
 * @param string $type Package type.
399
 * @return array full path to package
400
 * @link http://book.cakephp.org/2.0/en/core-utility-libraries/app.html#App::core
401
 */
402
	public static function core($type) {
403
		return array(CAKE . str_replace('/', DS, $type) . DS);
404
	}
405
 
406
/**
407
 * Returns an array of objects of the given type.
408
 *
409
 * Example usage:
410
 *
411
 * `App::objects('plugin');` returns `array('DebugKit', 'Blog', 'User');`
412
 *
413
 * `App::objects('Controller');` returns `array('PagesController', 'BlogController');`
414
 *
415
 * You can also search only within a plugin's objects by using the plugin dot
416
 * syntax.
417
 *
418
 * `App::objects('MyPlugin.Model');` returns `array('MyPluginPost', 'MyPluginComment');`
419
 *
420
 * When scanning directories, files and directories beginning with `.` will be excluded as these
421
 * are commonly used by version control systems.
422
 *
423
 * @param string $type Type of object, i.e. 'Model', 'Controller', 'View/Helper', 'file', 'class' or 'plugin'
424
 * @param string|array $path Optional Scan only the path given. If null, paths for the chosen type will be used.
425
 * @param bool $cache Set to false to rescan objects of the chosen type. Defaults to true.
426
 * @return mixed Either false on incorrect / miss. Or an array of found objects.
427
 * @link http://book.cakephp.org/2.0/en/core-utility-libraries/app.html#App::objects
428
 */
429
	public static function objects($type, $path = null, $cache = true) {
430
		if (empty(static::$_objects) && $cache === true) {
431
			static::$_objects = (array)Cache::read('object_map', '_cake_core_');
432
		}
433
 
434
		$extension = '/\.php$/';
435
		$includeDirectories = false;
436
		$name = $type;
437
 
438
		if ($type === 'plugin') {
439
			$type = 'plugins';
440
		}
441
 
442
		if ($type === 'plugins') {
443
			$extension = '/.*/';
444
			$includeDirectories = true;
445
		}
446
 
447
		list($plugin, $type) = pluginSplit($type);
448
 
449
		if (isset(static::$legacy[$type . 's'])) {
450
			$type = static::$legacy[$type . 's'];
451
		}
452
 
453
		if ($type === 'file' && !$path) {
454
			return false;
455
		} elseif ($type === 'file') {
456
			$extension = '/\.php$/';
457
			$name = $type . str_replace(DS, '', $path);
458
		}
459
 
460
		$cacheLocation = empty($plugin) ? 'app' : $plugin;
461
 
462
		if ($cache !== true || !isset(static::$_objects[$cacheLocation][$name])) {
463
			$objects = array();
464
 
465
			if (empty($path)) {
466
				$path = static::path($type, $plugin);
467
			}
468
 
469
			foreach ((array)$path as $dir) {
470
				if ($dir != APP && is_dir($dir)) {
471
					$files = new RegexIterator(new DirectoryIterator($dir), $extension);
472
					foreach ($files as $file) {
473
						$fileName = basename($file);
474
						if (!$file->isDot() && $fileName[0] !== '.') {
475
							$isDir = $file->isDir();
476
							if ($isDir && $includeDirectories) {
477
								$objects[] = $fileName;
478
							} elseif (!$includeDirectories && !$isDir) {
479
								$objects[] = substr($fileName, 0, -4);
480
							}
481
						}
482
					}
483
				}
484
			}
485
 
486
			if ($type !== 'file') {
487
				foreach ($objects as $key => $value) {
488
					$objects[$key] = Inflector::camelize($value);
489
				}
490
			}
491
 
492
			sort($objects);
493
			if ($plugin) {
494
				return $objects;
495
			}
496
 
497
			static::$_objects[$cacheLocation][$name] = $objects;
498
			if ($cache) {
499
				static::$_objectCacheChange = true;
500
			}
501
		}
502
 
503
		return static::$_objects[$cacheLocation][$name];
504
	}
505
 
506
/**
507
 * Declares a package for a class. This package location will be used
508
 * by the automatic class loader if the class is tried to be used
509
 *
510
 * Usage:
511
 *
512
 * `App::uses('MyCustomController', 'Controller');` will setup the class to be found under Controller package
513
 *
514
 * `App::uses('MyHelper', 'MyPlugin.View/Helper');` will setup the helper class to be found in plugin's helper package
515
 *
516
 * @param string $className the name of the class to configure package for
517
 * @param string $location the package name
518
 * @return void
519
 * @link http://book.cakephp.org/2.0/en/core-utility-libraries/app.html#App::uses
520
 */
521
	public static function uses($className, $location) {
522
		static::$_classMap[$className] = $location;
523
	}
524
 
525
/**
526
 * Method to handle the automatic class loading. It will look for each class' package
527
 * defined using App::uses() and with this information it will resolve the package name to a full path
528
 * to load the class from. File name for each class should follow the class name. For instance,
529
 * if a class is name `MyCustomClass` the file name should be `MyCustomClass.php`
530
 *
531
 * @param string $className the name of the class to load
532
 * @return bool
533
 */
534
	public static function load($className) {
535
		if (!isset(static::$_classMap[$className])) {
536
			return false;
537
		}
538
		if (strpos($className, '..') !== false) {
539
			return false;
540
		}
541
 
542
		$parts = explode('.', static::$_classMap[$className], 2);
543
		list($plugin, $package) = count($parts) > 1 ? $parts : array(null, current($parts));
544
 
545
		$file = static::_mapped($className, $plugin);
546
		if ($file) {
547
			return include $file;
548
		}
549
		$paths = static::path($package, $plugin);
550
 
551
		if (empty($plugin)) {
552
			$appLibs = empty(static::$_packages['Lib']) ? APPLIBS : current(static::$_packages['Lib']);
553
			$paths[] = $appLibs . $package . DS;
554
			$paths[] = APP . $package . DS;
555
			$paths[] = CAKE . $package . DS;
556
		} else {
557
			$pluginPath = CakePlugin::path($plugin);
558
			$paths[] = $pluginPath . 'Lib' . DS . $package . DS;
559
			$paths[] = $pluginPath . $package . DS;
560
		}
561
 
562
		$normalizedClassName = str_replace('\\', DS, $className);
563
		foreach ($paths as $path) {
564
			$file = $path . $normalizedClassName . '.php';
565
			if (file_exists($file)) {
566
				static::_map($file, $className, $plugin);
567
				return include $file;
568
			}
569
		}
570
 
571
		return false;
572
	}
573
 
574
/**
575
 * Returns the package name where a class was defined to be located at
576
 *
577
 * @param string $className name of the class to obtain the package name from
578
 * @return string|null Package name, or null if not declared
579
 * @link http://book.cakephp.org/2.0/en/core-utility-libraries/app.html#App::location
580
 */
581
	public static function location($className) {
582
		if (!empty(static::$_classMap[$className])) {
583
			return static::$_classMap[$className];
584
		}
585
		return null;
586
	}
587
 
588
/**
589
 * Finds classes based on $name or specific file(s) to search. Calling App::import() will
590
 * not construct any classes contained in the files. It will only find and require() the file.
591
 *
592
 * @param string|array $type The type of Class if passed as a string, or all params can be passed as
593
 *   a single array to $type.
594
 * @param string $name Name of the Class or a unique name for the file
595
 * @param bool|array $parent boolean true if Class Parent should be searched, accepts key => value
596
 *   array('parent' => $parent, 'file' => $file, 'search' => $search, 'ext' => '$ext');
597
 *   $ext allows setting the extension of the file name
598
 *   based on Inflector::underscore($name) . ".$ext";
599
 * @param array $search paths to search for files, array('path 1', 'path 2', 'path 3');
600
 * @param string $file full name of the file to search for including extension
601
 * @param bool $return Return the loaded file, the file must have a return
602
 *   statement in it to work: return $variable;
603
 * @return bool true if Class is already in memory or if file is found and loaded, false if not
604
 * @link http://book.cakephp.org/2.0/en/core-utility-libraries/app.html#including-files-with-app-import
605
 */
606
	public static function import($type = null, $name = null, $parent = true, $search = array(), $file = null, $return = false) {
607
		$ext = null;
608
 
609
		if (is_array($type)) {
610
			extract($type, EXTR_OVERWRITE);
611
		}
612
 
613
		if (is_array($parent)) {
614
			extract($parent, EXTR_OVERWRITE);
615
		}
616
 
617
		if (!$name && !$file) {
618
			return false;
619
		}
620
 
621
		if (is_array($name)) {
622
			foreach ($name as $class) {
623
				if (!App::import(compact('type', 'parent', 'search', 'file', 'return') + array('name' => $class))) {
624
					return false;
625
				}
626
			}
627
			return true;
628
		}
629
 
630
		$originalType = strtolower($type);
631
		$specialPackage = in_array($originalType, array('file', 'vendor'));
632
		if (!$specialPackage && isset(static::$legacy[$originalType . 's'])) {
633
			$type = static::$legacy[$originalType . 's'];
634
		}
635
		list($plugin, $name) = pluginSplit($name);
636
		if (!empty($plugin)) {
637
			if (!CakePlugin::loaded($plugin)) {
638
				return false;
639
			}
640
		}
641
 
642
		if (!$specialPackage) {
643
			return static::_loadClass($name, $plugin, $type, $originalType, $parent);
644
		}
645
 
646
		if ($originalType === 'file' && !empty($file)) {
647
			return static::_loadFile($name, $plugin, $search, $file, $return);
648
		}
649
 
650
		if ($originalType === 'vendor') {
651
			return static::_loadVendor($name, $plugin, $file, $ext);
652
		}
653
 
654
		return false;
655
	}
656
 
657
/**
658
 * Helper function to include classes
659
 * This is a compatibility wrapper around using App::uses() and automatic class loading
660
 *
661
 * @param string $name unique name of the file for identifying it inside the application
662
 * @param string $plugin camel cased plugin name if any
663
 * @param string $type name of the packed where the class is located
664
 * @param string $originalType type name as supplied initially by the user
665
 * @param bool $parent whether to load the class parent or not
666
 * @return bool true indicating the successful load and existence of the class
667
 */
668
	protected static function _loadClass($name, $plugin, $type, $originalType, $parent) {
669
		if ($type === 'Console/Command' && $name === 'Shell') {
670
			$type = 'Console';
671
		} elseif (isset(static::$types[$originalType]['suffix'])) {
672
			$suffix = static::$types[$originalType]['suffix'];
673
			$name .= ($suffix === $name) ? '' : $suffix;
674
		}
675
		if ($parent && isset(static::$types[$originalType]['extends'])) {
676
			$extends = static::$types[$originalType]['extends'];
677
			$extendType = $type;
678
			if (strpos($extends, '/') !== false) {
679
				$parts = explode('/', $extends);
680
				$extends = array_pop($parts);
681
				$extendType = implode('/', $parts);
682
			}
683
			App::uses($extends, $extendType);
684
			if ($plugin && in_array($originalType, array('controller', 'model'))) {
685
				App::uses($plugin . $extends, $plugin . '.' . $type);
686
			}
687
		}
688
		if ($plugin) {
689
			$plugin .= '.';
690
		}
691
		$name = Inflector::camelize($name);
692
		App::uses($name, $plugin . $type);
693
		return class_exists($name);
694
	}
695
 
696
/**
697
 * Helper function to include single files
698
 *
699
 * @param string $name unique name of the file for identifying it inside the application
700
 * @param string $plugin camel cased plugin name if any
701
 * @param array $search list of paths to search the file into
702
 * @param string $file filename if known, the $name param will be used otherwise
703
 * @param bool $return whether this function should return the contents of the file after being parsed by php or just a success notice
704
 * @return mixed if $return contents of the file after php parses it, boolean indicating success otherwise
705
 */
706
	protected static function _loadFile($name, $plugin, $search, $file, $return) {
707
		$mapped = static::_mapped($name, $plugin);
708
		if ($mapped) {
709
			$file = $mapped;
710
		} elseif (!empty($search)) {
711
			foreach ($search as $path) {
712
				$found = false;
713
				if (file_exists($path . $file)) {
714
					$file = $path . $file;
715
					$found = true;
716
					break;
717
				}
718
				if (empty($found)) {
719
					$file = false;
720
				}
721
			}
722
		}
723
		if (!empty($file) && file_exists($file)) {
724
			static::_map($file, $name, $plugin);
725
			$returnValue = include $file;
726
			if ($return) {
727
				return $returnValue;
728
			}
729
			return (bool)$returnValue;
730
		}
731
		return false;
732
	}
733
 
734
/**
735
 * Helper function to load files from vendors folders
736
 *
737
 * @param string $name unique name of the file for identifying it inside the application
738
 * @param string $plugin camel cased plugin name if any
739
 * @param string $file file name if known
740
 * @param string $ext file extension if known
741
 * @return bool true if the file was loaded successfully, false otherwise
742
 */
743
	protected static function _loadVendor($name, $plugin, $file, $ext) {
744
		if ($mapped = static::_mapped($name, $plugin)) {
745
			return (bool)include_once $mapped;
746
		}
747
		$fileTries = array();
748
		$paths = ($plugin) ? App::path('vendors', $plugin) : App::path('vendors');
749
		if (empty($ext)) {
750
			$ext = 'php';
751
		}
752
		if (empty($file)) {
753
			$fileTries[] = $name . '.' . $ext;
754
			$fileTries[] = Inflector::underscore($name) . '.' . $ext;
755
		} else {
756
			$fileTries[] = $file;
757
		}
758
 
759
		foreach ($fileTries as $file) {
760
			foreach ($paths as $path) {
761
				if (file_exists($path . $file)) {
762
					static::_map($path . $file, $name, $plugin);
763
					return (bool)include $path . $file;
764
				}
765
			}
766
		}
767
		return false;
768
	}
769
 
770
/**
771
 * Initializes the cache for App, registers a shutdown function.
772
 *
773
 * @return void
774
 */
775
	public static function init() {
776
		static::$_map += (array)Cache::read('file_map', '_cake_core_');
777
		register_shutdown_function(array('App', 'shutdown'));
778
	}
779
 
780
/**
781
 * Maps the $name to the $file.
782
 *
783
 * @param string $file full path to file
784
 * @param string $name unique name for this map
785
 * @param string $plugin camelized if object is from a plugin, the name of the plugin
786
 * @return void
787
 */
788
	protected static function _map($file, $name, $plugin = null) {
789
		$key = $name;
790
		if ($plugin) {
791
			$key = 'plugin.' . $name;
792
		}
793
		if ($plugin && empty(static::$_map[$name])) {
794
			static::$_map[$key] = $file;
795
		}
796
		if (!$plugin && empty(static::$_map['plugin.' . $name])) {
797
			static::$_map[$key] = $file;
798
		}
799
		if (!static::$bootstrapping) {
800
			static::$_cacheChange = true;
801
		}
802
	}
803
 
804
/**
805
 * Returns a file's complete path.
806
 *
807
 * @param string $name unique name
808
 * @param string $plugin camelized if object is from a plugin, the name of the plugin
809
 * @return mixed file path if found, false otherwise
810
 */
811
	protected static function _mapped($name, $plugin = null) {
812
		$key = $name;
813
		if ($plugin) {
814
			$key = 'plugin.' . $name;
815
		}
816
		return isset(static::$_map[$key]) ? static::$_map[$key] : false;
817
	}
818
 
819
/**
820
 * Sets then returns the templates for each customizable package path
821
 *
822
 * @return array templates for each customizable package path
823
 */
824
	protected static function _packageFormat() {
825
		if (empty(static::$_packageFormat)) {
826
			static::$_packageFormat = array(
827
				'Model' => array(
828
					'%s' . 'Model' . DS
829
				),
830
				'Model/Behavior' => array(
831
					'%s' . 'Model' . DS . 'Behavior' . DS
832
				),
833
				'Model/Datasource' => array(
834
					'%s' . 'Model' . DS . 'Datasource' . DS
835
				),
836
				'Model/Datasource/Database' => array(
837
					'%s' . 'Model' . DS . 'Datasource' . DS . 'Database' . DS
838
				),
839
				'Model/Datasource/Session' => array(
840
					'%s' . 'Model' . DS . 'Datasource' . DS . 'Session' . DS
841
				),
842
				'Controller' => array(
843
					'%s' . 'Controller' . DS
844
				),
845
				'Controller/Component' => array(
846
					'%s' . 'Controller' . DS . 'Component' . DS
847
				),
848
				'Controller/Component/Auth' => array(
849
					'%s' . 'Controller' . DS . 'Component' . DS . 'Auth' . DS
850
				),
851
				'Controller/Component/Acl' => array(
852
					'%s' . 'Controller' . DS . 'Component' . DS . 'Acl' . DS
853
				),
854
				'View' => array(
855
					'%s' . 'View' . DS
856
				),
857
				'View/Helper' => array(
858
					'%s' . 'View' . DS . 'Helper' . DS
859
				),
860
				'Console' => array(
861
					'%s' . 'Console' . DS
862
				),
863
				'Console/Command' => array(
864
					'%s' . 'Console' . DS . 'Command' . DS
865
				),
866
				'Console/Command/Task' => array(
867
					'%s' . 'Console' . DS . 'Command' . DS . 'Task' . DS
868
				),
869
				'Lib' => array(
870
					'%s' . 'Lib' . DS
871
				),
872
				'Locale' => array(
873
					'%s' . 'Locale' . DS
874
				),
875
				'Vendor' => array(
876
					'%s' . 'Vendor' . DS,
877
					ROOT . DS . 'vendors' . DS,
878
					dirname(dirname(CAKE)) . DS . 'vendors' . DS
879
				),
880
				'Plugin' => array(
881
					APP . 'Plugin' . DS,
882
					ROOT . DS . 'plugins' . DS,
883
					dirname(dirname(CAKE)) . DS . 'plugins' . DS
884
				)
885
			);
886
		}
887
 
888
		return static::$_packageFormat;
889
	}
890
 
891
/**
892
 * Object destructor.
893
 *
894
 * Writes cache file if changes have been made to the $_map. Also, check if a fatal
895
 * error happened and call the handler.
896
 *
897
 * @return void
898
 */
899
	public static function shutdown() {
900
		if (static::$_cacheChange) {
901
			Cache::write('file_map', array_filter(static::$_map), '_cake_core_');
902
		}
903
		if (static::$_objectCacheChange) {
904
			Cache::write('object_map', static::$_objects, '_cake_core_');
905
		}
906
		static::_checkFatalError();
907
	}
908
 
909
/**
910
 * Check if a fatal error happened and trigger the configured handler if configured
911
 *
912
 * @return void
913
 */
914
	protected static function _checkFatalError() {
915
		$lastError = error_get_last();
916
		if (!is_array($lastError)) {
917
			return;
918
		}
919
 
920
		list(, $log) = ErrorHandler::mapErrorCode($lastError['type']);
921
		if ($log !== LOG_ERR) {
922
			return;
923
		}
924
 
925
		if (PHP_SAPI === 'cli') {
926
			$errorHandler = Configure::read('Error.consoleHandler');
927
		} else {
928
			$errorHandler = Configure::read('Error.handler');
929
		}
930
		if (!is_callable($errorHandler)) {
931
			return;
932
		}
933
		call_user_func($errorHandler, $lastError['type'], $lastError['message'], $lastError['file'], $lastError['line'], array());
934
	}
935
 
936
}