sfProjectConfiguration.class.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596
  1. <?php
  2. /*
  3. * This file is part of the symfony package.
  4. * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
  5. *
  6. * For the full copyright and license information, please view the LICENSE
  7. * file that was distributed with this source code.
  8. */
  9. /**
  10. * sfProjectConfiguration represents a configuration for a symfony project.
  11. *
  12. * @package symfony
  13. * @subpackage config
  14. * @author Fabien Potencier <fabien.potencier@symfony-project.com>
  15. * @version SVN: $Id: sfProjectConfiguration.class.php 15805 2009-02-26 10:05:08Z fabien $
  16. */
  17. class sfProjectConfiguration
  18. {
  19. protected
  20. $rootDir = null,
  21. $symfonyLibDir = null,
  22. $plugins = array('sfPropelPlugin'),
  23. $pluginPaths = array(),
  24. $overriddenPluginPaths = array(),
  25. $pluginConfigurations = array(),
  26. $pluginsLoaded = false;
  27. static protected
  28. $active = null;
  29. /**
  30. * Constructor.
  31. *
  32. * @param string $rootDir The project root directory
  33. * @param sfEventDispatcher $dispatcher The event dispatcher
  34. */
  35. public function __construct($rootDir = null, sfEventDispatcher $dispatcher = null)
  36. {
  37. if (is_null(sfProjectConfiguration::$active) || $this instanceof sfApplicationConfiguration)
  38. {
  39. sfProjectConfiguration::$active = $this;
  40. }
  41. $this->rootDir = is_null($rootDir) ? self::guessRootDir() : realpath($rootDir);
  42. $this->symfonyLibDir = realpath(dirname(__FILE__).'/..');
  43. $this->dispatcher = is_null($dispatcher) ? new sfEventDispatcher() : $dispatcher;
  44. ini_set('magic_quotes_runtime', 'off');
  45. sfConfig::set('sf_symfony_lib_dir', $this->symfonyLibDir);
  46. $this->setRootDir($this->rootDir);
  47. $this->setup();
  48. $this->loadPlugins();
  49. }
  50. /**
  51. * Setups the current configuration.
  52. *
  53. * Override this method if you want to customize your project configuration.
  54. */
  55. public function setup()
  56. {
  57. }
  58. /**
  59. * Loads the project's plugin configurations.
  60. */
  61. public function loadPlugins()
  62. {
  63. foreach ($this->getPluginPaths() as $path)
  64. {
  65. if (false === $plugin = array_search($path, $this->overriddenPluginPaths))
  66. {
  67. $plugin = basename($path);
  68. }
  69. $class = $plugin.'Configuration';
  70. if (is_readable($file = sprintf('%s/config/%s.class.php', $path, $class)))
  71. {
  72. require_once $file;
  73. $configuration = new $class($this, $path, $plugin);
  74. }
  75. else
  76. {
  77. $configuration = new sfPluginConfigurationGeneric($this, $path, $plugin);
  78. }
  79. $this->pluginConfigurations[$plugin] = $configuration;
  80. }
  81. $this->pluginsLoaded = true;
  82. }
  83. /**
  84. * Sets the project root directory.
  85. *
  86. * @param string $rootDir The project root directory
  87. */
  88. public function setRootDir($rootDir)
  89. {
  90. $this->rootDir = $rootDir;
  91. sfConfig::add(array(
  92. 'sf_root_dir' => $rootDir,
  93. // global directory structure
  94. 'sf_apps_dir' => $rootDir.DIRECTORY_SEPARATOR.'apps',
  95. 'sf_lib_dir' => $rootDir.DIRECTORY_SEPARATOR.'lib',
  96. 'sf_log_dir' => $rootDir.DIRECTORY_SEPARATOR.'log',
  97. 'sf_data_dir' => $rootDir.DIRECTORY_SEPARATOR.'data',
  98. 'sf_config_dir' => $rootDir.DIRECTORY_SEPARATOR.'config',
  99. 'sf_test_dir' => $rootDir.DIRECTORY_SEPARATOR.'test',
  100. 'sf_doc_dir' => $rootDir.DIRECTORY_SEPARATOR.'doc',
  101. 'sf_plugins_dir' => $rootDir.DIRECTORY_SEPARATOR.'plugins',
  102. ));
  103. $this->setWebDir($rootDir.DIRECTORY_SEPARATOR.'web');
  104. $this->setCacheDir($rootDir.DIRECTORY_SEPARATOR.'cache');
  105. }
  106. /**
  107. * Returns the project root directory.
  108. *
  109. * @return string The project root directory
  110. */
  111. public function getRootDir()
  112. {
  113. return $this->rootDir;
  114. }
  115. /**
  116. * Sets the cache root directory.
  117. *
  118. * @param string $cacheDir The absolute path to the cache dir.
  119. */
  120. public function setCacheDir($cacheDir)
  121. {
  122. sfConfig::set('sf_cache_dir', $cacheDir);
  123. }
  124. /**
  125. * Sets the log directory.
  126. *
  127. * @param string $logDir The absolute path to the log dir.
  128. */
  129. public function setLogDir($logDir)
  130. {
  131. sfConfig::set('sf_log_dir', $logDir);
  132. }
  133. /**
  134. * Sets the web root directory.
  135. *
  136. * @param string $webDir The absolute path to the web dir.
  137. */
  138. public function setWebDir($webDir)
  139. {
  140. sfConfig::add(array(
  141. 'sf_web_dir' => $webDir,
  142. 'sf_upload_dir' => $webDir.DIRECTORY_SEPARATOR.'uploads',
  143. ));
  144. }
  145. /**
  146. * Gets directories where model classes are stored. The order of returned paths is lowest precedence
  147. * to highest precedence.
  148. *
  149. * @return array An array of directories
  150. */
  151. public function getModelDirs()
  152. {
  153. return array_merge(
  154. $this->getPluginSubPaths('/lib/model'), // plugins
  155. array(sfConfig::get('sf_lib_dir').'/model') // project
  156. );
  157. }
  158. /**
  159. * Gets directories where template files are stored for a generator class and a specific theme.
  160. *
  161. * @param string $class The generator class name
  162. * @param string $theme The theme name
  163. *
  164. * @return array An array of directories
  165. */
  166. public function getGeneratorTemplateDirs($class, $theme)
  167. {
  168. return array_merge(
  169. array(sfConfig::get('sf_data_dir').'/generator/'.$class.'/'.$theme.'/template'), // project
  170. $this->getPluginSubPaths('/data/generator/'.$class.'/'.$theme.'/template'), // plugins
  171. array(sfConfig::get('sf_data_dir').'/generator/'.$class.'/default/template'), // project (default theme)
  172. $this->getPluginSubPaths('/data/generator/'.$class.'/default/template') // plugins (default theme)
  173. );
  174. }
  175. /**
  176. * Gets directories where the skeleton is stored for a generator class and a specific theme.
  177. *
  178. * @param string $class The generator class name
  179. * @param string $theme The theme name
  180. *
  181. * @return array An array of directories
  182. */
  183. public function getGeneratorSkeletonDirs($class, $theme)
  184. {
  185. return array_merge(
  186. array(sfConfig::get('sf_data_dir').'/generator/'.$class.'/'.$theme.'/skeleton'), // project
  187. $this->getPluginSubPaths('/data/generator/'.$class.'/'.$theme.'/skeleton'), // plugins
  188. array(sfConfig::get('sf_data_dir').'/generator/'.$class.'/default/skeleton'), // project (default theme)
  189. $this->getPluginSubPaths('/data/generator/'.$class.'/default/skeleton') // plugins (default theme)
  190. );
  191. }
  192. /**
  193. * Gets the template to use for a generator class.
  194. *
  195. * @param string $class The generator class name
  196. * @param string $theme The theme name
  197. * @param string $path The template path
  198. *
  199. * @return string A template path
  200. *
  201. * @throws sfException
  202. */
  203. public function getGeneratorTemplate($class, $theme, $path)
  204. {
  205. $dirs = $this->getGeneratorTemplateDirs($class, $theme);
  206. foreach ($dirs as $dir)
  207. {
  208. if (is_readable($dir.'/'.$path))
  209. {
  210. return $dir.'/'.$path;
  211. }
  212. }
  213. throw new sfException(sprintf('Unable to load "%s" generator template in: %s.', $path, implode(', ', $dirs)));
  214. }
  215. /**
  216. * Gets the configuration file paths for a given relative configuration path.
  217. *
  218. * @param string $configPath The configuration path
  219. *
  220. * @return array An array of paths
  221. */
  222. public function getConfigPaths($configPath)
  223. {
  224. $globalConfigPath = basename(dirname($configPath)).'/'.basename($configPath);
  225. $files = array(
  226. sfConfig::get('sf_symfony_lib_dir').'/config/'.$globalConfigPath, // symfony
  227. );
  228. foreach ($this->getPluginPaths() as $path)
  229. {
  230. if (is_file($file = $path.'/'.$globalConfigPath))
  231. {
  232. $files[] = $file; // plugins
  233. }
  234. }
  235. $files = array_merge($files, array(
  236. sfConfig::get('sf_root_dir').'/'.$globalConfigPath, // project
  237. sfConfig::get('sf_root_dir').'/'.$configPath, // project
  238. ));
  239. foreach ($this->getPluginPaths() as $path)
  240. {
  241. if (is_file($file = $path.'/'.$configPath))
  242. {
  243. $files[] = $file; // plugins
  244. }
  245. }
  246. $configs = array();
  247. foreach (array_unique($files) as $file)
  248. {
  249. if (is_readable($file))
  250. {
  251. $configs[] = $file;
  252. }
  253. }
  254. return $configs;
  255. }
  256. /**
  257. * Sets the enabled plugins.
  258. *
  259. * @param array An array of plugin names
  260. *
  261. * @throws LogicException If plugins have already been loaded
  262. */
  263. public function setPlugins(array $plugins)
  264. {
  265. if ($this->pluginsLoaded)
  266. {
  267. throw new LogicException('Plugins have already been loaded.');
  268. }
  269. $this->plugins = $plugins;
  270. $this->pluginPaths = array();
  271. }
  272. /**
  273. * Enables a plugin or a list of plugins.
  274. *
  275. * @param array|string A plugin name or a plugin list
  276. */
  277. public function enablePlugins($plugins)
  278. {
  279. $this->setPlugins(array_merge($this->plugins, is_array($plugins) ? $plugins : array($plugins)));
  280. }
  281. /**
  282. * Disables a plugin.
  283. *
  284. * @param array|string A plugin name or a plugin list
  285. *
  286. * @throws LogicException If plugins have already been loaded
  287. */
  288. public function disablePlugins($plugins)
  289. {
  290. if ($this->pluginsLoaded)
  291. {
  292. throw new LogicException('Plugins have already been loaded.');
  293. }
  294. if (!is_array($plugins))
  295. {
  296. $plugins = array($plugins);
  297. }
  298. foreach ($plugins as $plugin)
  299. {
  300. if (false !== $pos = array_search($plugin, $this->plugins))
  301. {
  302. unset($this->plugins[$pos]);
  303. }
  304. else
  305. {
  306. throw new InvalidArgumentException(sprintf('The plugin "%s" does not exist.', $plugin));
  307. }
  308. }
  309. $this->pluginPaths = array();
  310. }
  311. /**
  312. * Enabled all installed plugins except the one given as argument.
  313. *
  314. * @param array|string A plugin name or a plugin list
  315. *
  316. * @throws LogicException If plugins have already been loaded
  317. */
  318. public function enableAllPluginsExcept($plugins = array())
  319. {
  320. if ($this->pluginsLoaded)
  321. {
  322. throw new LogicException('Plugins have already been loaded.');
  323. }
  324. $this->plugins = array();
  325. foreach ($this->getAllPluginPaths() as $plugin => $path)
  326. {
  327. $this->plugins[] = $plugin;
  328. }
  329. $this->disablePlugins($plugins);
  330. }
  331. /**
  332. * Gets the list of enabled plugins.
  333. *
  334. * @return array An array of enabled plugins
  335. */
  336. public function getPlugins()
  337. {
  338. return $this->plugins;
  339. }
  340. /**
  341. * Gets the paths plugin sub-directories, minding overloaded plugins.
  342. *
  343. * @param string $subPath The subdirectory to look for
  344. *
  345. * @return array The plugin paths.
  346. */
  347. public function getPluginSubPaths($subPath = '')
  348. {
  349. if (array_key_exists($subPath, $this->pluginPaths))
  350. {
  351. return $this->pluginPaths[$subPath];
  352. }
  353. $this->pluginPaths[$subPath] = array();
  354. $pluginPaths = $this->getPluginPaths();
  355. foreach ($pluginPaths as $pluginPath)
  356. {
  357. if (is_dir($pluginPath.$subPath))
  358. {
  359. $this->pluginPaths[$subPath][] = $pluginPath.$subPath;
  360. }
  361. }
  362. return $this->pluginPaths[$subPath];
  363. }
  364. /**
  365. * Gets the paths to plugins root directories, minding overloaded plugins.
  366. *
  367. * @return array The plugin root paths.
  368. */
  369. public function getPluginPaths()
  370. {
  371. if (array_key_exists('', $this->pluginPaths))
  372. {
  373. return $this->pluginPaths[''];
  374. }
  375. $pluginPaths = $this->getAllPluginPaths();
  376. $this->pluginPaths[''] = array();
  377. foreach ($this->getPlugins() as $plugin)
  378. {
  379. if (isset($pluginPaths[$plugin]))
  380. {
  381. $this->pluginPaths[''][] = $pluginPaths[$plugin];
  382. }
  383. else
  384. {
  385. throw new InvalidArgumentException(sprintf('The plugin "%s" does not exist.', $plugin));
  386. }
  387. }
  388. return $this->pluginPaths[''];
  389. }
  390. /**
  391. * Returns an array of paths for all available plugins.
  392. *
  393. * @return array
  394. */
  395. public function getAllPluginPaths()
  396. {
  397. $pluginPaths = array();
  398. $finder = sfFinder::type('dir')->maxdepth(0)->follow_link()->name('*Plugin');
  399. $dirs = array(
  400. sfConfig::get('sf_symfony_lib_dir').'/plugins',
  401. sfConfig::get('sf_plugins_dir'),
  402. );
  403. foreach ($finder->in($dirs) as $path)
  404. {
  405. $pluginPaths[basename($path)] = $path;
  406. }
  407. foreach ($this->overriddenPluginPaths as $plugin => $path)
  408. {
  409. $pluginPaths[$plugin] = $path;
  410. }
  411. return $pluginPaths;
  412. }
  413. /**
  414. * Manually sets the location of a particular plugin.
  415. *
  416. * This method can be used to ease functional testing of plugins. It is not
  417. * intended to support sharing plugins between projects, as many plugins
  418. * save project specific code (to /lib/form/base, for example).
  419. *
  420. * @param string $plugin
  421. * @param string $path
  422. */
  423. public function setPluginPath($plugin, $path)
  424. {
  425. $this->overriddenPluginPaths[$plugin] = realpath($path);
  426. }
  427. /**
  428. * Returns the configuration for the requested plugin.
  429. *
  430. * @param string $name
  431. *
  432. * @return sfPluginConfiguration
  433. */
  434. public function getPluginConfiguration($name)
  435. {
  436. if (!isset($this->pluginConfigurations[$name]))
  437. {
  438. throw new InvalidArgumentException(sprintf('There is no configuration object for the "%s" object.', $name));
  439. }
  440. return $this->pluginConfigurations[$name];
  441. }
  442. /**
  443. * Returns the event dispatcher.
  444. *
  445. * @return sfEventDispatcher A sfEventDispatcher instance
  446. */
  447. public function getEventDispatcher()
  448. {
  449. return $this->dispatcher;
  450. }
  451. /**
  452. * Returns the symfony lib directory.
  453. *
  454. * @return string The symfony lib directory
  455. */
  456. public function getSymfonyLibDir()
  457. {
  458. return $this->symfonyLibDir;
  459. }
  460. /**
  461. * Returns the active configuration.
  462. *
  463. * @return sfProjectConfiguration The current sfProjectConfiguration instance
  464. */
  465. static public function getActive()
  466. {
  467. if (is_null(sfProjectConfiguration::$active))
  468. {
  469. throw new RuntimeException('There is no active configuration.');
  470. }
  471. return sfProjectConfiguration::$active;
  472. }
  473. static public function guessRootDir()
  474. {
  475. $r = new ReflectionClass('ProjectConfiguration');
  476. return realpath(dirname($r->getFileName()).'/..');
  477. }
  478. /**
  479. * Returns a sfApplicationConfiguration configuration for a given application.
  480. *
  481. * @param string $application An application name
  482. * @param string $environment The environment name
  483. * @param Boolean $debug true to enable debug mode
  484. * @param string $rootDir The project root directory
  485. * @param sfEventDispatcher $dispatcher An event dispatcher
  486. *
  487. * @return sfApplicationConfiguration A sfApplicationConfiguration instance
  488. */
  489. static public function getApplicationConfiguration($application, $environment, $debug, $rootDir = null, sfEventDispatcher $dispatcher = null)
  490. {
  491. $class = $application.'Configuration';
  492. if (is_null($rootDir))
  493. {
  494. $rootDir = self::guessRootDir();
  495. }
  496. if (!file_exists($file = $rootDir.'/apps/'.$application.'/config/'.$class.'.class.php'))
  497. {
  498. throw new InvalidArgumentException(sprintf('The application "%s" does not exist.', $application));
  499. }
  500. require_once $file;
  501. return new $class($environment, $debug, $rootDir, $dispatcher);
  502. }
  503. /**
  504. * Calls methods defined via sfEventDispatcher.
  505. *
  506. * @param string $method The method name
  507. * @param array $arguments The method arguments
  508. *
  509. * @return mixed The returned value of the called method
  510. */
  511. public function __call($method, $arguments)
  512. {
  513. $event = $this->dispatcher->notifyUntil(new sfEvent($this, 'configuration.method_not_found', array('method' => $method, 'arguments' => $arguments)));
  514. if (!$event->isProcessed())
  515. {
  516. throw new sfException(sprintf('Call to undefined method %s::%s.', get_class($this), $method));
  517. }
  518. return $event->getReturnValue();
  519. }
  520. }