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

Debug toolbar