PageRenderTime 34ms CodeModel.GetById 1ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/Cake/Core/App.php

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