PageRenderTime 45ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/classes/core/PKPApplication.inc.php

https://github.com/jalilyacob/pkp-lib
PHP | 603 lines | 356 code | 76 blank | 171 comment | 32 complexity | 0ca27d6cf4178640202c0b9777027987 MD5 | raw file
Possible License(s): LGPL-2.1
  1. <?php
  2. /**
  3. * @file classes/core/PKPApplication.inc.php
  4. *
  5. * Copyright (c) 2000-2013 John Willinsky
  6. * Distributed under the GNU GPL v2. For full terms see the file docs/COPYING.
  7. *
  8. * @class PKPApplication
  9. * @ingroup core
  10. *
  11. * @brief Class describing this application.
  12. *
  13. */
  14. define_exposed('REALLY_BIG_NUMBER', 10000);
  15. define('ROUTE_COMPONENT', 'component');
  16. define('ROUTE_PAGE', 'page');
  17. define('CONTEXT_SITE', 0);
  18. define('CONTEXT_ID_NONE', 0);
  19. define('REVIEW_ROUND_NONE', 0);
  20. define('ASSOC_TYPE_PRODUCTION_ASSIGNMENT', 0x0000202);
  21. define('ASSOC_TYPE_SUBMISSION_FILE', 0x0000203);
  22. define('ASSOC_TYPE_REVIEW_RESPONSE', 0x0000204);
  23. define('ASSOC_TYPE_REVIEW_ASSIGNMENT', 0x0000205);
  24. define('ASSOC_TYPE_SUBMISSION_EMAIL_LOG_ENTRY', 0x0000206);
  25. define('ASSOC_TYPE_WORKFLOW_STAGE', 0x0000207);
  26. define('ASSOC_TYPE_NOTE', 0x0000208);
  27. define('ASSOC_TYPE_ANNOUNCEMENT', 0x000020A);
  28. define('ASSOC_TYPE_REVIEW_ROUND', 0x000020B);
  29. define('ASSOC_TYPE_SUBMISSION_FILES', 0x000020F);
  30. define('ASSOC_TYPE_PUBLISHED_SUBMISSION', 0x0000210);
  31. define('ASSOC_TYPE_PLUGIN', 0x0000211);
  32. define('ASSOC_TYPE_USER', 0x0001000); // This value used because of bug #6068
  33. define('ASSOC_TYPE_USER_GROUP', 0x0100002);
  34. define('ASSOC_TYPE_CITATION', 0x0100003);
  35. define('ASSOC_TYPE_AUTHOR', 0x0100004);
  36. define('ASSOC_TYPE_EDITOR', 0x0100005);
  37. define('ASSOC_TYPE_SIGNOFF', 0x0100006);
  38. define('ASSOC_TYPE_USER_ROLES', 0x0100007);
  39. define('ASSOC_TYPE_ACCESSIBLE_WORKFLOW_STAGES', 0x0100008);
  40. define('ASSOC_TYPE_SUBMISSION', 0x0100009);
  41. define_exposed('WORKFLOW_STAGE_ID_PUBLISHED', 0); // FIXME? See bug #6463.
  42. define_exposed('WORKFLOW_STAGE_ID_SUBMISSION', 1);
  43. define_exposed('WORKFLOW_STAGE_ID_INTERNAL_REVIEW', 2);
  44. define_exposed('WORKFLOW_STAGE_ID_EXTERNAL_REVIEW', 3);
  45. define_exposed('WORKFLOW_STAGE_ID_EDITING', 4);
  46. define_exposed('WORKFLOW_STAGE_ID_PRODUCTION', 5);
  47. // FIXME: these were defined in userGroup. they need to be moved somewhere with classes that do mapping.
  48. define('WORKFLOW_STAGE_PATH_SUBMISSION', 'submission');
  49. define('WORKFLOW_STAGE_PATH_INTERNAL_REVIEW', 'internalReview');
  50. define('WORKFLOW_STAGE_PATH_EXTERNAL_REVIEW', 'externalReview');
  51. define('WORKFLOW_STAGE_PATH_EDITING', 'editorial');
  52. define('WORKFLOW_STAGE_PATH_PRODUCTION', 'production');
  53. // To expose LISTBUILDER_SOURCE_TYPE_... constants via JS
  54. import('lib.pkp.classes.controllers.listbuilder.ListbuilderHandler');
  55. // To expose ORDER_CATEGORY_GRID_... constants via JS
  56. import('lib.pkp.classes.controllers.grid.feature.OrderCategoryGridItemsFeature');
  57. class PKPApplication {
  58. var $enabledProducts;
  59. var $allProducts;
  60. function PKPApplication() {
  61. // Seed random number generator
  62. mt_srand(((double) microtime()) * 1000000);
  63. import('lib.pkp.classes.core.Core');
  64. import('lib.pkp.classes.core.String');
  65. import('lib.pkp.classes.core.Registry');
  66. import('lib.pkp.classes.config.Config');
  67. if (Config::getVar('debug', 'display_errors')) {
  68. // Try to switch off normal error display when error display
  69. // is being managed by us.
  70. ini_set('display_errors', false);
  71. }
  72. Registry::set('application', $this);
  73. import('lib.pkp.classes.db.DAORegistry');
  74. import('lib.pkp.classes.db.XMLDAO');
  75. import('lib.pkp.classes.cache.CacheManager');
  76. import('classes.security.Validation');
  77. import('lib.pkp.classes.session.SessionManager');
  78. import('classes.template.TemplateManager');
  79. import('classes.notification.NotificationManager');
  80. import('lib.pkp.classes.plugins.PluginRegistry');
  81. import('lib.pkp.classes.plugins.HookRegistry');
  82. import('classes.i18n.AppLocale');
  83. String::init();
  84. set_error_handler(array($this, 'errorHandler'));
  85. $microTime = Core::microtime();
  86. Registry::set('system.debug.startTime', $microTime);
  87. $notes = array();
  88. Registry::set('system.debug.notes', $notes);
  89. if (Config::getVar('general', 'installed')) {
  90. // Initialize database connection
  91. $conn = DBConnection::getInstance();
  92. if (!$conn->isConnected()) {
  93. if (Config::getVar('database', 'debug')) {
  94. $dbconn =& $conn->getDBConn();
  95. fatalError('Database connection failed: ' . $dbconn->errorMsg());
  96. } else {
  97. fatalError('Database connection failed!');
  98. }
  99. }
  100. }
  101. }
  102. /**
  103. * Get the current application object
  104. * @return Application
  105. */
  106. static function &getApplication() {
  107. $application =& Registry::get('application');
  108. return $application;
  109. }
  110. /**
  111. * Get the request implementation singleton
  112. * @return Request
  113. */
  114. static function &getRequest() {
  115. $request =& Registry::get('request', true, null);
  116. if (is_null($request)) {
  117. import('classes.core.Request');
  118. // Implicitly set request by ref in the registry
  119. $request = new Request();
  120. }
  121. return $request;
  122. }
  123. /**
  124. * Get the dispatcher implementation singleton
  125. * @return Dispatcher
  126. */
  127. static function &getDispatcher() {
  128. $dispatcher =& Registry::get('dispatcher', true, null);
  129. if (is_null($dispatcher)) {
  130. import('lib.pkp.classes.core.Dispatcher');
  131. // Implicitly set dispatcher by ref in the registry
  132. $dispatcher = new Dispatcher();
  133. // Inject dependency
  134. $dispatcher->setApplication(PKPApplication::getApplication());
  135. // Inject router configuration
  136. $dispatcher->addRouterName('lib.pkp.classes.core.PKPComponentRouter', ROUTE_COMPONENT);
  137. $dispatcher->addRouterName('classes.core.PageRouter', ROUTE_PAGE);
  138. }
  139. return $dispatcher;
  140. }
  141. /**
  142. * This executes the application by delegating the
  143. * request to the dispatcher.
  144. */
  145. function execute() {
  146. // Dispatch the request to the correct handler
  147. $dispatcher = $this->getDispatcher();
  148. $dispatcher->dispatch($this->getRequest());
  149. }
  150. /**
  151. * Get the symbolic name of this application
  152. * @return string
  153. */
  154. function getName() {
  155. return 'pkp-lib';
  156. }
  157. /**
  158. * Get the locale key for the name of this application.
  159. * @return string
  160. */
  161. function getNameKey() {
  162. // must be implemented by sub-classes
  163. assert(false);
  164. }
  165. /**
  166. * Get the "context depth" of this application, i.e. the number of
  167. * parts of the URL after index.php that represent the context of
  168. * the current request (e.g. Journal [1], or Conference and
  169. * Scheduled Conference [2]).
  170. * @return int
  171. */
  172. function getContextDepth() {
  173. // must be implemented by sub-classes
  174. assert(false);
  175. }
  176. /**
  177. * Get the list of the contexts available for this application
  178. * i.e. the various parameters that are needed to represent the
  179. * (e.g. array('journal') or array('conference', 'schedConf'))
  180. * @return Array
  181. */
  182. function getContextList() {
  183. // must be implemented by sub-classes
  184. assert(false);
  185. }
  186. /**
  187. * Get the URL to the XML descriptor for the current version of this
  188. * application.
  189. * @return string
  190. */
  191. function getVersionDescriptorUrl() {
  192. // must be implemented by sub-classes
  193. assert(false);
  194. }
  195. /**
  196. * This function retrieves all enabled product versions once
  197. * from the database and caches the result for further
  198. * access.
  199. *
  200. * @param $category string
  201. * @param $mainContextId integer Optional ID of the top-level context
  202. * (e.g. Journal, Conference, Press) to query for enabled products
  203. * @return array
  204. */
  205. function &getEnabledProducts($category = null, $mainContextId = null) {
  206. if (is_null($this->enabledProducts) || !is_null($mainContextId)) {
  207. $contextDepth = $this->getContextDepth();
  208. $settingContext = array();
  209. if ($contextDepth > 0) {
  210. $request = $this->getRequest();
  211. $router = $request->getRouter();
  212. if (is_null($mainContextId)) {
  213. // Try to identify the main context (e.g. journal, conference, press),
  214. // will be null if none found.
  215. $mainContext = $router->getContext($request, 1);
  216. if ($mainContext) $mainContextId = $mainContext->getId();
  217. }
  218. // Create the context for the setting if found
  219. if (!is_null($mainContextId)) $settingContext[] = $mainContextId;
  220. $settingContext = array_pad($settingContext, $contextDepth, 0);
  221. $settingContext = array_combine($this->getContextList(), $settingContext);
  222. }
  223. $versionDao = DAORegistry::getDAO('VersionDAO'); /* @var $versionDao VersionDAO */
  224. $this->enabledProducts =& $versionDao->getCurrentProducts($settingContext);
  225. }
  226. if (is_null($category)) {
  227. return $this->enabledProducts;
  228. } elseif (isset($this->enabledProducts[$category])) {
  229. return $this->enabledProducts[$category];
  230. } else {
  231. $returner = array();
  232. return $returner;
  233. }
  234. }
  235. /**
  236. * Get the list of plugin categories for this application.
  237. */
  238. function getPluginCategories() {
  239. // To be implemented by sub-classes
  240. assert(false);
  241. }
  242. /**
  243. * Return the current version of the application.
  244. * @return Version
  245. */
  246. function &getCurrentVersion() {
  247. $currentVersion =& $this->getEnabledProducts('core');
  248. assert(count($currentVersion)) == 1;
  249. return $currentVersion[$this->getName()];
  250. }
  251. /**
  252. * Get the map of DAOName => full.class.Path for this application.
  253. * @return array
  254. */
  255. function getDAOMap() {
  256. return array(
  257. 'AccessKeyDAO' => 'lib.pkp.classes.security.AccessKeyDAO',
  258. 'AuthSourceDAO' => 'lib.pkp.classes.security.AuthSourceDAO',
  259. 'CitationDAO' => 'lib.pkp.classes.citation.CitationDAO',
  260. 'ControlledVocabDAO' => 'lib.pkp.classes.controlledVocab.ControlledVocabDAO',
  261. 'ControlledVocabEntryDAO' => 'lib.pkp.classes.controlledVocab.ControlledVocabEntryDAO',
  262. 'CountryDAO' => 'lib.pkp.classes.i18n.CountryDAO',
  263. 'CurrencyDAO' => 'lib.pkp.classes.currency.CurrencyDAO',
  264. 'DataObjectTombstoneDAO' => 'lib.pkp.classes.tombstone.DataObjectTombstoneDAO',
  265. 'DataObjectTombstoneSettingsDAO' => 'lib.pkp.classes.tombstone.DataObjectTombstoneSettingsDAO',
  266. 'EditDecisionDAO' => 'lib.pkp.classes.submission.EditDecisionDAO',
  267. 'FilterDAO' => 'lib.pkp.classes.filter.FilterDAO',
  268. 'FilterGroupDAO' => 'lib.pkp.classes.filter.FilterGroupDAO',
  269. 'GenreDAO' => 'lib.pkp.classes.submission.GenreDAO',
  270. 'HelpTocDAO' => 'lib.pkp.classes.help.HelpTocDAO',
  271. 'HelpTopicDAO' => 'lib.pkp.classes.help.HelpTopicDAO',
  272. 'InterestDAO' => 'lib.pkp.classes.user.InterestDAO',
  273. 'InterestEntryDAO' => 'lib.pkp.classes.user.InterestEntryDAO',
  274. 'LanguageDAO' => 'lib.pkp.classes.language.LanguageDAO',
  275. 'LibraryFileDAO' => 'lib.pkp.classes.context.LibraryFileDAO',
  276. 'MetadataDescriptionDAO' => 'lib.pkp.classes.metadata.MetadataDescriptionDAO',
  277. 'NotificationDAO' => 'lib.pkp.classes.notification.NotificationDAO',
  278. 'NotificationMailListDAO' => 'lib.pkp.classes.notification.NotificationMailListDAO',
  279. 'NotificationSettingsDAO' => 'lib.pkp.classes.notification.NotificationSettingsDAO',
  280. 'NotificationSubscriptionSettingsDAO' => 'lib.pkp.classes.notification.NotificationSubscriptionSettingsDAO',
  281. 'ProcessDAO' => 'lib.pkp.classes.process.ProcessDAO',
  282. 'ReviewFilesDAO' => 'lib.pkp.classes.submission.ReviewFilesDAO',
  283. 'ReviewRoundDAO' => 'lib.pkp.classes.submission.reviewRound.ReviewRoundDAO',
  284. 'ScheduledTaskDAO' => 'lib.pkp.classes.scheduledTask.ScheduledTaskDAO',
  285. 'SessionDAO' => 'lib.pkp.classes.session.SessionDAO',
  286. 'SiteDAO' => 'lib.pkp.classes.site.SiteDAO',
  287. 'SiteSettingsDAO' => 'lib.pkp.classes.site.SiteSettingsDAO',
  288. 'SubmissionAgencyDAO' => 'lib.pkp.classes.submission.SubmissionAgencyDAO',
  289. 'SubmissionAgencyEntryDAO' => 'lib.pkp.classes.submission.SubmissionAgencyEntryDAO',
  290. 'SubmissionDisciplineDAO' => 'lib.pkp.classes.submission.SubmissionDisciplineDAO',
  291. 'SubmissionDisciplineEntryDAO' => 'lib.pkp.classes.submission.SubmissionDisciplineEntryDAO',
  292. 'SubmissionEmailLogDAO' => 'lib.pkp.classes.log.SubmissionEmailLogDAO',
  293. 'SubmissionFileEventLogDAO' => 'lib.pkp.classes.log.SubmissionFileEventLogDAO',
  294. 'SubmissionFileSignoffDAO' => 'lib.pkp.classes.submission.SubmissionFileSignoffDAO',
  295. 'SubmissionLanguageDAO' => 'lib.pkp.classes.submission.SubmissionLanguageDAO',
  296. 'SubmissionLanguageEntryDAO' => 'lib.pkp.classes.submission.SubmissionLanguageEntryDAO',
  297. 'SubmissionKeywordDAO' => 'lib.pkp.classes.submission.SubmissionKeywordDAO',
  298. 'SubmissionKeywordEntryDAO' => 'lib.pkp.classes.submission.SubmissionKeywordEntryDAO',
  299. 'SubmissionSubjectDAO' => 'lib.pkp.classes.submission.SubmissionSubjectDAO',
  300. 'SubmissionSubjectEntryDAO' => 'lib.pkp.classes.submission.SubmissionSubjectEntryDAO',
  301. 'TimeZoneDAO' => 'lib.pkp.classes.i18n.TimeZoneDAO',
  302. 'TemporaryFileDAO' => 'lib.pkp.classes.file.TemporaryFileDAO',
  303. 'UserGroupDAO' => 'lib.pkp.classes.security.UserGroupDAO',
  304. 'UserStageAssignmentDAO' => 'lib.pkp.classes.user.UserStageAssignmentDAO',
  305. 'VersionDAO' => 'lib.pkp.classes.site.VersionDAO',
  306. 'ViewsDAO' => 'lib.pkp.classes.views.ViewsDAO',
  307. 'XMLDAO' => 'lib.pkp.classes.db.XMLDAO'
  308. );
  309. }
  310. /**
  311. * Return the fully-qualified (e.g. page.name.ClassNameDAO) name of the
  312. * given DAO.
  313. * @param $name string
  314. * @return string
  315. */
  316. function getQualifiedDAOName($name) {
  317. $map =& Registry::get('daoMap', true, $this->getDAOMap());
  318. if (isset($map[$name])) return $map[$name];
  319. return null;
  320. }
  321. /**
  322. * Instantiate the help object for this application.
  323. * @return object
  324. */
  325. function &instantiateHelp() {
  326. // must be implemented by sub-classes
  327. assert(false);
  328. }
  329. /**
  330. * Custom error handler
  331. *
  332. * NB: Custom error handlers are called for all error levels
  333. * independent of the error_reporting parameter.
  334. * @param $errorno string
  335. * @param $errstr string
  336. * @param $errfile string
  337. * @param $errline string
  338. */
  339. function errorHandler($errorno, $errstr, $errfile, $errline) {
  340. // We only report/log errors if their corresponding
  341. // error level bit is set in error_reporting.
  342. // We have to check error_reporting() each time as
  343. // some application parts change the setting (e.g.
  344. // smarty, adodb, certain plugins).
  345. if(error_reporting() & $errorno) {
  346. if ($errorno == E_ERROR) {
  347. echo 'An error has occurred. Please check your PHP log file.';
  348. } elseif (Config::getVar('debug', 'display_errors')) {
  349. echo $this->buildErrorMessage($errorno, $errstr, $errfile, $errline) . "<br/>\n";
  350. }
  351. error_log($this->buildErrorMessage($errorno, $errstr, $errfile, $errline), 0);
  352. }
  353. }
  354. /**
  355. * Auxiliary function to errorHandler that returns a formatted error message.
  356. * Error type formatting code adapted from ash, http://ca3.php.net/manual/en/function.set-error-handler.php
  357. * @param $errorno string
  358. * @param $errstr string
  359. * @param $errfile string
  360. * @param $errline string
  361. * @return $message string
  362. */
  363. function buildErrorMessage($errorno, $errstr, $errfile, $errline) {
  364. $message = array();
  365. $errorType = array (
  366. E_ERROR => 'ERROR',
  367. E_WARNING => 'WARNING',
  368. E_PARSE => 'PARSING ERROR',
  369. E_NOTICE => 'NOTICE',
  370. E_CORE_ERROR => 'CORE ERROR',
  371. E_CORE_WARNING => 'CORE WARNING',
  372. E_COMPILE_ERROR => 'COMPILE ERROR',
  373. E_COMPILE_WARNING => 'COMPILE WARNING',
  374. E_USER_ERROR => 'USER ERROR',
  375. E_USER_WARNING => 'USER WARNING',
  376. E_USER_NOTICE => 'USER NOTICE',
  377. );
  378. if (array_key_exists($errorno, $errorType)) {
  379. $type = $errorType[$errorno];
  380. } else {
  381. $type = 'CAUGHT EXCEPTION';
  382. }
  383. // Return abridged message if strict error or notice (since they are more common)
  384. // This also avoids infinite loops when E_STRICT (=deprecation level) error
  385. // reporting is switched on.
  386. $shortErrors = E_NOTICE;
  387. if (defined('E_STRICT')) $shortErrors |= E_STRICT;
  388. if (defined('E_DEPRECATED')) $shortErrors |= E_DEPRECATED;
  389. if ($errorno & $shortErrors) {
  390. return $type . ': ' . $errstr . ' (' . $errfile . ':' . $errline . ')';
  391. }
  392. $message[] = $this->getName() . ' has produced an error';
  393. $message[] = ' Message: ' . $type . ': ' . $errstr;
  394. $message[] = ' In file: ' . $errfile;
  395. $message[] = ' At line: ' . $errline;
  396. $message[] = ' Stacktrace: ';
  397. if(Config::getVar('debug', 'show_stacktrace')) {
  398. $trace = debug_backtrace();
  399. // Remove the call to fatalError from the call trace.
  400. array_shift($trace);
  401. // Back-trace pretty-printer adapted from the following URL:
  402. // http://ca3.php.net/manual/en/function.debug-backtrace.php
  403. // Thanks to diz at ysagoon dot com
  404. foreach ($trace as $bt) {
  405. $args = '';
  406. if (isset($bt['args'])) foreach ($bt['args'] as $a) {
  407. if (!empty($args)) {
  408. $args .= ', ';
  409. }
  410. switch (gettype($a)) {
  411. case 'integer':
  412. case 'double':
  413. $args .= $a;
  414. break;
  415. case 'string':
  416. $a = htmlspecialchars($a);
  417. $args .= "\"$a\"";
  418. break;
  419. case 'array':
  420. $args .= 'Array('.count($a).')';
  421. break;
  422. case 'object':
  423. $args .= 'Object('.get_class($a).')';
  424. break;
  425. case 'resource':
  426. $args .= 'Resource('.strstr($a, '#').')';
  427. break;
  428. case 'boolean':
  429. $args .= $a ? 'True' : 'False';
  430. break;
  431. case 'NULL':
  432. $args .= 'Null';
  433. break;
  434. default:
  435. $args .= 'Unknown';
  436. }
  437. }
  438. $class = isset($bt['class'])?$bt['class']:'';
  439. $type = isset($bt['type'])?$bt['type']:'';
  440. $function = isset($bt['function'])?$bt['function']:'';
  441. $file = isset($bt['file'])?$bt['file']:'(unknown)';
  442. $line = isset($bt['line'])?$bt['line']:'(unknown)';
  443. $message[] = " File: {$file} line {$line}";
  444. $message[] = " Function: {$class}{$type}{$function}($args)";
  445. }
  446. }
  447. static $dbServerInfo;
  448. if (!isset($dbServerInfo) && Config::getVar('general', 'installed')) {
  449. $dbconn =& DBConnection::getConn();
  450. $dbServerInfo = $dbconn->ServerInfo();
  451. }
  452. $message[] = " Server info:";
  453. $message[] = " OS: " . Core::serverPHPOS();
  454. $message[] = " PHP Version: " . Core::serverPHPVersion();
  455. $message[] = " Apache Version: " . (function_exists('apache_get_version') ? apache_get_version() : 'N/A');
  456. $message[] = " DB Driver: " . Config::getVar('database', 'driver');
  457. if (isset($dbServerInfo)) $message[] = " DB server version: " . (empty($dbServerInfo['description']) ? $dbServerInfo['version'] : $dbServerInfo['description']);
  458. return implode("\n", $message);
  459. }
  460. /**
  461. * Define a constant so that it can be exposed to the JS front-end.
  462. * @param $name string
  463. * @param $value mixed
  464. */
  465. static function defineExposedConstant($name, $value) {
  466. define($name, $value);
  467. assert(preg_match('/^[a-zA-Z_]+$/', $name));
  468. $constants =& PKPApplication::getExposedConstants();
  469. $constants[$name] = $value;
  470. }
  471. /**
  472. * Get an associative array of defined constants that should be exposed
  473. * to the JS front-end.
  474. * @return array
  475. */
  476. static function &getExposedConstants() {
  477. static $exposedConstants = array();
  478. return $exposedConstants;
  479. }
  480. /**
  481. * Get an array of locale keys that define strings that should be made available to
  482. * JavaScript classes in the JS front-end.
  483. * @return array
  484. */
  485. function getJSLocaleKeys() {
  486. $keys = array('form.dataHasChanged');
  487. return $keys;
  488. }
  489. /**
  490. * Get the top-level context DAO.
  491. */
  492. static function getContextDAO() {
  493. assert(false); // Must be implemented by subclasses
  494. }
  495. /**
  496. * Get the submission DAO.
  497. */
  498. static function getSubmissionDAO() {
  499. assert(false); // Must be implemented by subclasses
  500. }
  501. /**
  502. * Get the DAO for ROLE_ID_SUB_EDITOR roles.
  503. */
  504. static function getSubEditorDAO() {
  505. assert(false); // Must be implemented by subclasses
  506. }
  507. /**
  508. * Get the stages used by the application.
  509. */
  510. static function getApplicationStages() {
  511. assert(false); // Must be implemented by subclasses
  512. }
  513. /**
  514. * Get the file directory array map used by the application.
  515. * should return array('context' => ..., 'submission' => ...)
  516. */
  517. static function getFileDirectories() {
  518. assert(false); // Must be implemented by subclasses.
  519. }
  520. }
  521. /**
  522. * @see PKPApplication::defineExposedConstant()
  523. */
  524. function define_exposed($name, $value) {
  525. PKPApplication::defineExposedConstant($name, $value);
  526. }
  527. ?>