PageRenderTime 59ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/CakeLib/cake/libs/configure.php

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