Source for file Harmoni.class.php

Documentation is available at Harmoni.class.php

  1. <?php
  2. //require_once(HARMONI."architecture/harmoni/Harmoni.interface.php");
  3. require_once(HARMONI."actionHandler/ActionHandler.class.php");
  4. require_once(HARMONI."utilities/FieldSetValidator/ReferencedFieldSet.class.php");
  5. require_once(HARMONI."utilities/FieldSetValidator/FieldSet.class.php");
  6. require_once(HARMONI."languageLocalizer/LanguageLocalizer.class.php");
  7. require_once(HARMONI."architecture/harmoni/HarmoniConfig.class.php");
  8. require_once(HARMONI."architecture/request/RequestContext.class.php");
  9. require_once(HARMONI."architecture/harmoni/BrowseHistoryManager.class.php");
  10. require_once(HARMONI."actionHandler/DottedPairValidatorRule.class.php");
  11. require_once(HARMONI."/architecture/output/BasicOutputHandler.class.php");
  12. require_once(HARMONI."/architecture/output/BasicOutputHandlerConfigProperties.class.php");
  13. require_once(OKI2."/osid/OsidContext.php");
  14.  
  15. $__harmoni = null;
  16.  
  17. /**
  18. * The Harmoni class combines the functionality of login, authentication,
  19. * action-handling and theme-output. It makes use of the the
  20. * {@link ActionHandler} classes.
  21. *
  22. * The Harmoni class implements the Singleton pattern. There is only ever
  23. * on instance of the Harmoni object and it is accessed only via the
  24. * {@link instance Harmoni::instance()} method.
  25. *
  26. * @package harmoni.architecture
  27. *
  28. * @copyright Copyright &copy; 2005, Middlebury College
  29. * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License (GPL)
  30. *
  31. * @version $Id: Harmoni.class.php,v 1.53 2007/09/04 20:25:30 adamfranco Exp $
  32. ***/
  33. class Harmoni {
  34.  
  35. /*******************************************************
  36. * Class Methods - Instance-Creation/Singlton
  37. *********************************************************/
  38.  
  39.  
  40. /**
  41. * Get the instance of Harmoni.
  42. * The Harmoni class implements the Singleton pattern. There is only ever
  43. * one instance of the Harmoni object and it is accessed only via the
  44. * Harmoni::instance() method.
  45. *
  46. * @return object Harmoni
  47. * @access public
  48. * @since 5/26/05
  49. * @static
  50. */
  51. function instance () {
  52. if (!defined("HARMONI_INSTANTIATED")) {
  53. $GLOBALS['__harmoni'] = new Harmoni();
  54. define("HARMONI_INSTANTIATED", true);
  55. }
  56. return $GLOBALS['__harmoni'];
  57. }
  58.  
  59. /*******************************************************
  60. * Instance Variables
  61. *********************************************************/
  62.  
  63.  
  64. /**
  65. * @access private
  66. * @var string $_currentAction A dotted-pair module.action
  67. ***/
  68. var $_currentAction;
  69. /**
  70. * @access private
  71. * @var object OutputHandler $_outputHandler The handler we are using for output.
  72. ***/
  73. var $_outputHandler;
  74. /**
  75. * @access public
  76. * @var object $ActionHandler The {@link ActionHandler} object.
  77. ***/
  78. var $ActionHandler;
  79. /**
  80. * @access public
  81. * @var object RequestContext $request
  82. */
  83. var $request;
  84. /**
  85. * @access public
  86. * @var object BrowseHistoryManager $history
  87. */
  88. var $history;
  89. /**
  90. * @access public
  91. * @var object $config A {@link HarmoniConfig} {@link DataContainer} for Harmoni-specific options.
  92. ***/
  93. var $config;
  94. var $_attachedData;
  95. var $_preExecActions;
  96. var $_postExecActions;
  97. var $_postProcessAction;
  98. var $_postProcessIgnoreList;
  99. var $result;
  100.  
  101. /*******************************************************
  102. * Instance Methods
  103. *********************************************************/
  104.  
  105. /**
  106. * The constructor.
  107. * @access public
  108. * @return void
  109. ***/
  110. function Harmoni() {
  111. // Verify that there is only one instance of Harmoni.
  112. $backtrace = debug_backtrace();
  113. if (false && $GLOBALS['__harmoni']
  114. || !isset($backtrace[1])
  115. || !(strtolower($backtrace[1]['class']) == 'harmoni'
  116. && $backtrace[1]['function'] == 'instance'
  117. // && $backtrace[1]['type'] == '::' // PHP 5.2.1 seems to get this wrong
  118. ))
  119. {
  120. die("\n<dl style='border: 1px solid #F00; padding: 10px;'>"
  121. ."\n\t<dt><strong>Invalid Harmoni instantiation at...</strong></dt>"
  122. ."\n\t<dd> File: ".$backtrace[0]['file']
  123. ."\n\t\t<br/> Line: ".$backtrace[0]['line']
  124. ."\n\t</dd>"
  125. ."\n\t<dt><strong>Access Harmoni with <em>Harmoni::instance()</em></strong></dt>"
  126. ."\n\t<dt><strong>Backtrace:</strong></dt>"
  127. ."\n\t<dd>".printDebugBacktrace(debug_backtrace(), true)."</dd>"
  128. ."\n\t<dt><strong>PHP Version:</strong></dt>"
  129. ."\n\t<dd>".phpversion()."</dd>"
  130. ."\n</dl>");
  131. }
  132. $this->ActionHandler = new ActionHandler($this);
  133. // set up config options
  134. $this->config = new HarmoniConfig();
  135. // set up request context / handler
  136. $this->request = new RequestContext();
  137. // set up the history manager
  138. $this->history = new BrowseHistoryManager();
  139. $this->_attachedData = new ReferencedFieldSet();
  140. $this->_preExecActions = array();
  141. $this->_postExecActions = array();
  142. // Set up a default OutputHandler
  143. $osidContext = new OsidContext;
  144. $osidContext->assignContext('harmoni', $this);
  145. $configuration = new BasicOutputHandlerConfigProperties;
  146. $outputHandler = new BasicOutputHandler;
  147. $outputHandler->assignOsidContext($osidContext);
  148. $outputHandler->assignConfiguration($configuration);
  149. $this->attachOutputHandler($outputHandler);
  150. }
  151. /**
  152. * Adds an action, or multiple, (see the {@link ActionHandler}) to execute before executing the action requested by the end user.
  153. * @param string $action,... A number of actions (module.action) to execute.
  154. * @access public
  155. * @return void
  156. */
  157. function addPreExecActions($actions)
  158. {
  159. $args = func_get_args();
  160. $rule = DottedPairValidatorRule::getRule();
  161. foreach ($args as $arg) {
  162. if ($rule->check($arg)) $this->_preExecActions[] = $arg;
  163. }
  164. }
  165. /**
  166. * Adds an action, or multiple, (see the {@link ActionHandler}) to execute after executing the action requested by the end user.
  167. * @param string $action,... A number of actions (module.action) to execute.
  168. * @access public
  169. * @return void
  170. */
  171. function addPostExecActions($actions)
  172. {
  173. $args = func_get_args();
  174. $rule = DottedPairValidatorRule::getRule();
  175. foreach ($args as $arg) {
  176. if ($rule->check($arg)) $this->_postExecActions[] = $arg;
  177. }
  178. }
  179. /**
  180. * Sets the action to call after the browser-requested action has executed but before the output from that action is processed. The result from the previous action can be accessed as Harmoni::result.
  181. * @param string $action A dotted-pair action (module.action) to use for post processing.
  182. * @param optional array $ignore An array of dotted-pair actions for which we will NOT execute the post-process action.
  183. * @access public
  184. * @return void
  185. */
  186. function setPostProcessAction($action, $ignore=null)
  187. {
  188. $rule1 = DottedPairValidatorRule::getRule();
  189. $rule2 = ArrayValidatorRuleWithRule::getRule($rule1);
  190. ArgumentValidator::validate($action, $rule1);
  191. if ($ignore) ArgumentValidator::validate($ignore, $rule2);
  192. $this->_postProcessIgnoreList = $ignore?$ignore:array();
  193. $this->_postProcessAction = $action;
  194. }
  195. /**
  196. * Returns TRUE if $action is contained somewhere within the array of actions: $array.
  197. * @param string $action
  198. * @param array $array
  199. * @access private
  200. * @return bool
  201. */
  202. function _isActionInArray($action, $array)
  203. {
  204. if (in_array($action, $array)) return true;
  205. ereg("(.+)\.(.+)",$action,$r);
  206. $reqMod = $r[1];
  207. $reqAct = $r[2];
  208. foreach ($array as $pair) {
  209. ereg("(.+)\.(.+)",$pair,$r);
  210. $mod = $r[1];
  211. $act = $r[2];
  212. if ($mod == $reqMod && $act == "*") return true;
  213. }
  214. return false;
  215. }
  216. /**
  217. * Returns a pretty version string of our running Harmoni framework version.
  218. * @param optional string $versionStr An optional harmoni version string. If it is a partial string, we will return a full three-part version string.
  219. * @access public
  220. * @return string
  221. */
  222. function getVersionStr($versionStr=null) {
  223. if ($versionStr) $harmoniVersion = $versionStr;
  224. else include HARMONI."version.inc.php";
  225. $ar = $this->_getVersionParts($harmoniVersion);
  226. return $ar[0] . "." . $ar[1] . "." . $ar[2];
  227. }
  228. /**
  229. * Returns the numeric representation of our framework version. The format is XXMMRR, two digits for each of the major, minor and release numbers. NOTE: leading 0's are omitted.
  230. * @param optional string $versionStr An optional harmoni version string "M[.m[.r]]" to turn into a number. Otherwise, the actual running Harmoni version number will be used.
  231. * @access public
  232. * @return integer
  233. */
  234. function getVersionNumber($versionStr=null)
  235. {
  236. if ($versionStr) $harmoniVersion = $versionStr;
  237. else include HARMONI."version.inc.php";
  238. $ar = $this->_getVersionParts($harmoniVersion);
  239. $num = (integer) ereg_replace("^0+","",sprintf("%02d%02d%02d",$ar[0],$ar[1], $ar[2]));
  240. return $num;
  241. }
  242. /**
  243. * Returns an array of the Harmoni version string containing the major, minor and release numbers, in that order.
  244. * @param string $string
  245. * @access public
  246. * @return array
  247. */
  248. function _getVersionParts($string)
  249. {
  250. ereg("([0-9]+)(\.([0-9]+))?(\.([0-9]+))?", $string, $matches);
  251. $major = (integer) $matches[1];
  252. $minor = (integer) $matches[3]?$matches[3]:0;
  253. $release = (integer) $matches[5]?$matches[5]:0;
  254. return array($major, $minor, $release);
  255. }
  256. /**
  257. * @return ref mixed
  258. * @param string $key
  259. * @param mixed $value
  260. * Attaches some arbitrary data to the Harmoni object so that actions or later
  261. * functions can make use of it.
  262. */
  263. function attachData($key, $value) {
  264. $this->_attachedData->set($key,$value);
  265. return $value;
  266. }
  267. /**
  268. * Same as {@link Harmoni::getAttachedData getAttachedData()}.
  269. * @return ref mixed
  270. * @param string $key
  271. * Returns the data attached by {@link Harmoni::attachData} referenced by $key.
  272. * @deprecated 12/27/03 See getAttachedData()
  273. */
  274. function getData($key) {
  275. return $this->_attachedData->get($key);
  276. }
  277. /**
  278. * @return ref mixed
  279. * @param string $key
  280. * Returns the data attached by {@link Harmoni::attachData} referenced by $key.
  281. */
  282. function getAttachedData($key) {
  283. return $this->_attachedData->get($key);
  284. }
  285. /**
  286. * @return void
  287. * @param string $module
  288. * @param string $action
  289. * An alias for {@link ActionHandler::forward()}. Purely for convenience.
  290. */
  291. function forward($module, $action) {
  292. $this->ActionHandler->forward($module, $action);
  293. }
  294. function _detectCurrentAction() {
  295. // if we've already run, get out
  296. if ($this->_currentAction) return;
  297. // find what action we are trying to execute
  298. $pair = $this->request->getRequestedModuleAction();
  299. // now, let's find out what we got handed. could be any of:
  300. // 1) module.action <-- great
  301. // 2) module. <-- ok, we'll use default action
  302. // 3) module <-- same as above
  303. // 3) .action <-- no good!
  304. // 4) . <-- ok, we'll use defaults
  305. if (ereg("^[[:alnum:]_-]+\.[[:alnum:]_-]+$",$pair))
  306. list ($module, $action) = explode(".",$pair);
  307. else if (ereg("^[[:alnum:]_-]+\.?$",$pair)) {
  308. $module = str_replace(".","",$pair);
  309. $action = $this->config->get("defaultAction");
  310. } else if (ereg("^\.[[:alnum:]_-]+$",$pair)) {
  311. // no good! throw an error
  312. throwError(new Error("Harmoni::execute() - Could not execute action '$pair' - a module needs to be specified!","Harmoni",true));
  313. return false;
  314. } else if (ereg("^\.?$",$pair)) {
  315. $module = $this->config->get("defaultModule");
  316. $action = $this->config->get("defaultAction");
  317. }
  318. // that should cover it -- we now have a module and action to work with!
  319. $pair = "$module.$action";
  320. $this->setCurrentAction($pair);
  321. }
  322. /**
  323. * Executes the Harmoni procedures: action
  324. * processing and themed output to the browser. Certain options must be
  325. * set before execute() can be called.
  326. * @access public
  327. * @return void
  328. ***/
  329. function execute() {
  330. $this->config->checkAll();
  331. // update the request handler
  332. $this->request->update();
  333. // detect the current action
  334. $this->_detectCurrentAction();
  335. // check if we have any pre-exec actions. if so, execute them
  336. if (count($this->_preExecActions)) {
  337. foreach ($this->_preExecActions as $pair) {
  338. $this->ActionHandler->executePair($pair);
  339. }
  340. }
  341. // check if we've still got the same action
  342. $pair = $this->getCurrentAction();
  343. list($module,$action) = explode(".",$pair);
  344. // ok, now we execute the action
  345. // 1) call the action, get the return result
  346. // 2) Take whatever it returns (true, false, or Layout)
  347. // 3) Pass that on to the theme/OutputHandler
  348. // That's it! program finished!
  349.  
  350. ob_start();
  351. $this->result =$this->ActionHandler->execute($module, $action);
  352. $this->printedResult = ob_get_contents();
  353. ob_end_clean();
  354. $lastExecutedAction = $this->ActionHandler->lastExecutedAction();
  355.  
  356. // if we have a post-process action, let's try executing it.
  357. if (isset($this->_postProcessAction) &&
  358. !$this->_isActionInArray($lastExecutedAction, $this->_postProcessIgnoreList))
  359. {
  360. $this->result =$this->ActionHandler->executePair($this->_postProcessAction);
  361. }
  362. // check if we have any post-exec actions. if so, execute them
  363. if (count($this->_postExecActions)) {
  364. foreach ($this->_postExecActions as $pair) {
  365. $this->ActionHandler->executePair($pair);
  366. }
  367. }
  368.  
  369. $this->_outputHandler->output($this->result, $this->printedResult);
  370. }
  371. /**
  372. * Set the OutputHandler to use for theming the output.
  373. *
  374. * @param object $outputHandler
  375. * @return void
  376. * @access public
  377. * @since 4/5/05
  378. */
  379. function attachOutputHandler ( $outputHandler ) {
  380. $this->_outputHandler =$outputHandler;
  381. }
  382. /**
  383. * Get the OutputHandler used for theming the output.
  384. *
  385. * @return object $outputHandler
  386. * @access public
  387. * @since 4/5/05
  388. */
  389. function getOutputHandler () {
  390. return $this->_outputHandler;
  391. }
  392. /**
  393. * Returns the current action.
  394. * @access public
  395. * @return string A dotted-pair action.
  396. ***/
  397. function getCurrentAction() {
  398. return $this->_currentAction;
  399. }
  400. /**
  401. * Sets the current Harmoni action.
  402. * @param string $action A dotted-pair action string.
  403. * @access public
  404. * @return void
  405. ***/
  406. function setCurrentAction($action) {
  407. ArgumentValidator::validate($action, DottedPairValidatorRule::getRule());
  408. $this->_currentAction = $action;
  409. }
  410. /**
  411. * Starts the session.
  412. * @access public
  413. * @return void
  414. ***/
  415. function startSession() {
  416. // let's start the session
  417. if (session_id()) return;
  418. ini_set("session.use_cookies",
  419. ($this->config->get("sessionUseCookies")?1:0));
  420. ini_set("session.use_only_cookies",
  421. ($this->config->get("sessionUseOnlyCookies")?1:0));
  422. session_name($this->config->get("sessionName"));
  423. if (!isset($_COOKIE[$this->config->get("sessionName")])
  424. && (!isset($_REQUEST[$this->config->get("sessionName")])
  425. && !$this->config->get("sessionUseOnlyCookies")))
  426. {
  427. session_id(uniqid(str_replace(".","",$_SERVER['REMOTE_ADDR']))); // make new session id.
  428. }
  429. $path = $this->config->get("sessionCookiePath");
  430. if ($path[strlen($path) - 1] != '/')
  431. $path .= '/';
  432. session_set_cookie_params(0, $path, $this->config->get("sessionCookieDomain"));
  433. session_start(); // yay!
  434. }
  435.  
  436. }
  437.  
  438. ?>

Documentation generated on Wed, 19 Sep 2007 10:23:34 -0400 by phpDocumentor 1.3.0RC3