Source for file ActionHandler.class.php

Documentation is available at ActionHandler.class.php

  1. <?php
  2. /**
  3. * @package harmoni.actions
  4. *
  5. * @copyright Copyright &copy; 2005, Middlebury College
  6. * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License (GPL)
  7. *
  8. * @version $Id: ActionHandler.class.php,v 1.22 2007/09/04 20:25:29 adamfranco Exp $
  9. */
  10.  
  11. //require_once(HARMONI."actionHandler/ActionHandler.interface.php");
  12. require_once(HARMONI."actionHandler/DottedPairValidatorRule.class.php");
  13.  
  14. require_once(HARMONI."actionHandler/actionSources/ClassesActionSource.class.php");
  15. require_once(HARMONI."actionHandler/actionSources/FlatFileActionSource.class.php");
  16. require_once(HARMONI."actionHandler/actionSources/ClassMethodsActionSource.class.php");
  17.  
  18. require_once(HARMONI."architecture/events/EventTrigger.abstract.php");
  19.  
  20. /**
  21. * @const integer MODULES_FOLDERS Specifies that modules are stored in folders.
  22. * @package harmoni.actions
  23. ***/
  24. define("MODULES_FOLDERS",1);
  25.  
  26. /**
  27. * @const integer MODULES_CLASSES Specifies that modules are stored in classes.
  28. * @package harmoni.actions
  29. ***/
  30. define("MODULES_CLASSES",2);
  31.  
  32. /**
  33. * @const integer ACTIONS_CLASSES Specifies that actions are stored as classes.
  34. * @package harmoni.actions
  35. ***/
  36. define("ACTIONS_CLASSES",1);
  37.  
  38. /**
  39. * @const integer ACTIONS_CLASS_METHODS Specifies that actions are stored as class-methods.
  40. * @package harmoni.actions
  41. ***/
  42. define("ACTIONS_CLASS_METHODS",2);
  43.  
  44. /**
  45. * @const integer ACTIONS_FLATFILES Specifies that actions are stored as flat files to be included.
  46. * @package harmoni.actions
  47. ***/
  48. define("ACTIONS_FLATFILES",3);
  49.  
  50. /**
  51. * @const string ACTIONS_CLASSES_METHOD The method name to call when executing actions
  52. * that are classes. (value = 'execute')
  53. * @package harmoni.actions
  54. ***/
  55. define("ACTIONS_CLASSES_METHOD","execute");
  56.  
  57. /**
  58. * The ActionHandler interface defines the required methods for an ActionHandler class.
  59. *
  60. * The ActionHandler takes care of: authentication, and then executing PHP
  61. * scripts in a user-defined place with user-defined options.
  62. *
  63. * An action can be a: flat PHP file, an entire PHP class, or a specific method
  64. * within a class. Actions are organized into modules, which can be: a folder or a class.
  65. * A specific action is referenced by "module.action" certain module/action options
  66. * are not compatible (such as modules=folders and actions=method-within-class).
  67. *
  68. * An action is passed the following items:<br/>
  69. * <li>The {@link Harmoni} object.
  70. *
  71. * @package harmoni.actions
  72. *
  73. * @copyright Copyright &copy; 2005, Middlebury College
  74. * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License (GPL)
  75. *
  76. * @version $Id: ActionHandler.class.php,v 1.22 2007/09/04 20:25:29 adamfranco Exp $
  77. */
  78. class ActionHandler extends EventTrigger {
  79. /**
  80. * @access private
  81. * @var object $_harmoni A reference to the {@link Harmoni} object.
  82. ***/
  83. var $_harmoni;
  84. /**
  85. * @access private
  86. * @var array $_threads A hashed-array of subsequent actions for any given action.
  87. ***/
  88. var $_threads;
  89. /**
  90. * @access private
  91. * @var array $_modulesSettings A variable for backward compatibility. Don't worry about it.
  92. ***/
  93. var $_modulesSettings;
  94. /**
  95. * @access private
  96. * @var array $_actionSources An array of {@link ActionSource} objects.
  97. */
  98. var $_actionSources;
  99. /**
  100. * @access private
  101. * @var array $_actionsExecuted An array of actions we've already executed. Used in order
  102. * to avoid infinite-loops created by stupid people creating stupid action threads.
  103. ***/
  104. var $_actionsExecuted;
  105. /**
  106. * @access private
  107. * @var string $_forwardToAction
  108. */
  109. var $_forwardToAction = false;
  110. /**
  111. * @access private
  112. * @var string $_executing
  113. */
  114. var $_executing = false;
  115. /**
  116. * The constructor.
  117. * @param object $httpVars A {@link FieldSet} object of HTTP variables.
  118. * @param optional object $context A {@link Context} object.
  119. * @param optional object $loginState A {@link LoginState} object.
  120. * @access public
  121. * @return void
  122. ***/
  123. function ActionHandler($harmoni) {
  124. $this->_harmoni =$harmoni;
  125. $this->_actionsExecuted = array();
  126. $this->_threads = array();
  127. $this->_actionSources = array();
  128. $this->_modulesSettings["callCount"] = 0;
  129. }
  130. /**
  131. * If called within an executing action, will execute $module.$action
  132. * after calling action has stopped.
  133. * @param string $module The module, or a "module.action" pair, in which case the second parameter can be omitted.
  134. * @param optional string $action The action to execute.
  135. * @access public
  136. * @return void
  137. */
  138. function forward( $module, $action=null ) {
  139. debug::output("attempting to forward to action: $module.$action",DEBUG_SYS5,"ActionHandler");
  140. $test = DottedPairValidatorRule::getRule();
  141. if ($this->_executing) {
  142. if ($test->check($module) && !$action) {
  143. $this->_forwardToAction = $module;
  144. }
  145. if ($module && $action) {
  146. $this->_forwardToAction = $module . "." . $action;
  147. }
  148. $this->triggerEvent("edu.middlebury.harmoni.actionhandler.action_forwarded", $this, array("from"=>$this->_executing, "to"=>$this->_forwardToAction));
  149. return;
  150. throwError( new Error("ActionHandler::forward($module, $action) - could not proceed. The action does not seem to be valid.","ActionHandler",true));
  151. }
  152. throwError( new Error("ActionHandler::forward($module, $action) - could not proceed. The ActionHandler is not currently executing any actions.","ActionHandler",true));
  153. }
  154. /**
  155. * The execute function takes a module and action. The method executes
  156. * the given action, taking the result and either executing another action
  157. * (based on the user specified options) or returning the result from the action.
  158. * @param string $module The module name.
  159. * @param string $action The action name.
  160. * @access public
  161. * @return ref mixed Returns whatever is recieved from the last action
  162. * to execute. Can be: a {@link Layout} object, TRUE/FALSE, etc.
  163. ***/
  164. function execute($module, $action) {
  165. $this->_executing = $module.".".$action;
  166. $result =$this->_execute($module, $action);
  167. $this->_executing = false;
  168. return $result;
  169. }
  170. /**
  171. * Executes the given action
  172. * @param string $module
  173. * @param string $action
  174. * @access private
  175. * @return mixed
  176. ***/
  177. function _execute($module, $action) {
  178. debug::output("executing action '$module.$action'...",DEBUG_SYS5,"ActionHandler");
  179. $_pair = "$module.$action";
  180. // if we've already executed this action, we're probably stuck
  181. // in an infinite loop. no good!
  182. if (in_array($_pair, $this->_actionsExecuted)) {
  183. throwError(new Error("ActionHandler::execute($_pair) - could not proceed:
  184. it seems we have already executed this action before.
  185. Are we in an infinite loop?","ActionHandler",true));
  186. return false;
  187. }
  188. // go through each of the ActionSources and see if they have an action to execute. if so, execute it and stop
  189. // cycling through them (only the first action will be executed).
  190. $executedAction = false;
  191. $result = null;
  192.  
  193. foreach (array_keys($this->_actionSources) as $sourceID) {
  194. $source =$this->_actionSources[$sourceID];
  195. if ($source->actionExists($module, $action)) {
  196. $result =$source->executeAction($module, $action, $this->_harmoni);
  197. $executedAction = true;
  198. break;
  199. }
  200. }
  201. if (!$executedAction) {
  202. throwError ( new Error("ActionHandler::execute($module, $action) - could not proceed: no action source could find an
  203. action to associate with this module/action pair.","ActionHandler",true));
  204. }
  205. // we've now executed this action -- add it to the array
  206. $this->_actionsExecuted[] = $_pair;
  207. $this->triggerEvent("edu.middlebury.harmoni.actionhandler.action_executed", $this, array("action"=>$_pair));
  208. // now that we have our $result, let's check if we should do anything
  209. // else or just return back to our caller.
  210. // if the action that was executing called forward(), execute that action.
  211. // otherwise, check if we have a thread to follow.
  212. if ($this->_forwardToAction) {
  213. $forward = $this->_forwardToAction;
  214. $this->_forwardToAction = false;
  215. return $this->_executePair($forward);
  216. }
  217. if (isset($this->_threads[$_pair])) {
  218. // we have a subsequent action defined...
  219. // if we failed and there's a fail defined
  220. if (!$result && ($failAction = $this->_threads[$_pair][0])) {
  221. return $this->_executePair($failAction);
  222. }
  223. // if we succeeded and there's a success action defined
  224. if ($result && ($successAction = $this->_threads[$_pair][1])) {
  225. return $this->_executePair($successAction);
  226. }
  227. }
  228. // otherwise, just return the darned result
  229. return $result;
  230.  
  231. // phew!
  232. }
  233. /**
  234. * Executes a module.action pair.
  235. * @param string $pair
  236. * @access private
  237. * @return mixed
  238. ***/
  239. function _executePair($pair) {
  240. list($module, $action) = explode(".",$pair);
  241. $res =$this->_execute($module, $action);
  242. return $res;
  243. }
  244. /**
  245. * Executes a module.action pair.
  246. * @param string $pair
  247. * @access public
  248. * @return mixed
  249. ***/
  250. function executePair($pair) {
  251. ArgumentValidator::validate($pair, DottedPairValidatorRule::getRule());
  252. $res =$this->_executePair($pair);
  253. return $res;
  254. }
  255. /**
  256. * Returns the last executed action.
  257. * @return string
  258. */
  259. function lastExecutedAction() {
  260. return $this->_actionsExecuted[count($this->_actionsExecuted)-1];
  261. }
  262. /**
  263. * Sets the location of the modules to use.
  264. * @param string $location The path to the modules.
  265. * @param integer $type Should be either MODULES_FOLDERS or MODULES_CLASSES
  266. * @param optional string $fileExtension If $type=MODULES_CLASSES, the string to append
  267. * onto the module name to find the class file (ie, ".class.php").
  268. * @use MODULES_FOLDERS
  269. * @use MODULES_CLASSES
  270. * @access public
  271. * @deprecated 5/28/2004 see {@link ActionHandler::addActionSource()}
  272. * @return void
  273. ***/
  274. function setModulesLocation($location, $type, $fileExtension=null) {
  275. // if $type=MODULES_CLASSES and $fileExtension is not set, throw an error
  276. if ($type==MODULES_CLASSES && !$fileExtension) {
  277. throwError(new Error("ActionHandler::setModulesLocation($location) - could not proceed: with \$type = MODULES_CLASSES you must specify the 3rd argument 'fileExtension'!","ActionHandler",true));
  278. return false;
  279. }
  280. $this->_modulesSettings["location"] = $location;
  281. $this->_modulesSettings["type"] = $type;
  282. $this->_modulesSettings["ext"] = $ext;
  283. $this->_modulesSettings["callCount"]++;
  284. if ($this->_modulesSettings["callCount"] == 2) $this->_compatActionSource();
  285. }
  286. /**
  287. * Sets the default way for how we locate actions. Action Types for
  288. * particular modules can be set with setActionsTypeForModulesLocation() method.
  289. * @param integer $type Should be any of ACTIONS_FLATFILES, ACTIONS_CLASSES, ACTIONS_CLASS_METHODS.
  290. * @param optional string $fileExtension If $type=ACTIONS_FLATFILES or ACTIONS_CLASSES, the extension to apply to
  291. * the action name to find the file (ie, ".inc.php" would give "action1name.inc.php").
  292. * @use ACTIONS_FLATFILES
  293. * @use ACTIONS_CLASSES
  294. * @use ACTIONS_CLASS_METHODS
  295. * @access public
  296. * @deprecated 5/28/2004 see {@link ActionHandler::addActionSource()}
  297. * @return void
  298. ***/
  299. function setActionsType($type, $fileExtension=null) {
  300. // we need a fileExtension for FLATFILES and CLASSES
  301. if (($type == ACTIONS_FLATFILES || $type == ACTIONS_CLASSES) && !$fileExtension) {
  302. throwError(new Error("ActionHandler::setActionsType - since \$type = ACTIONS_FLATFILE or ACTIONS_CLASSES, you must pass 2nd argument 'fileExtension'!","ActionHandler",true));
  303. return false;
  304. }
  305. $this->_modulesSettings["actionType"] = $type;
  306. $this->_modulesSettings["actionExt"] = $fileExtension;
  307. $this->_modulesSettings["callCount"]++;
  308. if ($this->_modulesSettings["callCount"] == 2) $this->_compatActionSource();
  309. }
  310. /**
  311. * For backward compatibility with deprecated functions -- will add an action source based on settings given with old functions.
  312. * @access private
  313. * @return void
  314. */
  315. function _compatActionSource()
  316. {
  317.  
  318. // we have three options here.
  319. // 1) modules = folders, actions = flat files
  320. // 2) modules = folders, actions = classes
  321. // 3) modules = classes, actions = methods
  322. if ($this->_modulesSettings["type"] == MODULES_FOLDERS && $this->_modulesSettings["actionType"] == ACTIONS_FLATFILES) {
  323. $this->addActionSource( new FlatFileActionSource($this->_modulesSettings["location"], $this->_modulesSettings["actionExt"]));
  324. }
  325. if ($this->_modulesSettings["type"] == MODULES_FOLDERS && $this->_modulesSettings["actionType"] == ACTIONS_CLASSSES) {
  326. $this->addActionSource( new ClassesActionSource($this->_modulesSettings["location"], $this->_modulesSettings["actionExt"]));
  327. }
  328. if ($this->_modulesSettings["type"] == MODULES_CLASSES && $this->_modulesSettings["actionType"] == ACTIONS_CLASS_METHODS) {
  329. $this->addActionSource( new ClassMethodsActionSource($this->_modulesSettings["location"], $this->_modulesSettings["ext"]));
  330. }
  331. // done.
  332. }
  333. /**
  334. * Adds a location for actions to the list of locations.
  335. * @param ref object $actionsTypeObject An {@link ActionSource} object, specifying how to handle the given directory.
  336. * @access public
  337. * @return void
  338. */
  339. function addActionSource( $actionSourceObject )
  340. {
  341. $this->_actionSources[] =$actionSourceObject;
  342. }
  343. /**
  344. * Adds to the action-processing thread. If $action is executed and it returns a failure
  345. * or success code, $actionOnFail will be executed afterwards if $action fails, otherwise,
  346. * $actionOnSuccess will be executed (or nothing will be if this option isn't included).
  347. * @param string $action A "module.action" string specifying which action to set the thread for.
  348. * @param string $actionOnFail A "module.action" string specifying what should be executed if
  349. * $action fails.
  350. * @param optional string $actionOnSuccess A "module.action" string specifying what should be executed
  351. * if $action succeeds.
  352. * @access public
  353. * @return void
  354. ***/
  355. function setActionThread($action, $actionOnFail, $actionOnSuccess=null) {
  356. // first, make sure that each thing we're passed is indeed a dotted pair
  357. $dp = DottedPairValidatorRule::getRule();
  358. ArgumentValidator::validate($action,$dp);
  359. ArgumentValidator::validate($actionOnFail,$dp);
  360. if ($actionOnSuccess)
  361. ArgumentValidator::validate($actionOnSuccess,$dp);
  362. // lets make sure they're not creating a circular loop
  363. if (($action == $actionOnFail) || ($action == $actionOnSuccess)) {
  364. throwError ( new Error("ActionHandler::setActionThread($action) - you may not
  365. specify an action on fail or succeed to forward to the same action.","ActionHandler",true));
  366. }
  367. // ok, now check if we've already defined a thread for $action.
  368. // if so, throw a WARNING
  369. if (isset($this->_threads[$action]))
  370. throwError(new Error("WARNING: An action thread for '$action' has already been defined! New thread will override the old one!","ActionHandler",false));
  371. // ok, let's do the dirty
  372. $this->_threads[$action] = array($actionOnFail,$actionOnSuccess);
  373. // done.
  374. }
  375. /**
  376. * Returns an array of actions that have been executed this session.
  377. * @access public
  378. * @return array
  379. ***/
  380. function getExecutedActions() {
  381. return $this->_actionsExecuted;
  382. }
  383. }
  384.  
  385. ?>

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