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

/library/Adapto/Handler/Action.php

http://github.com/egeniq/adapto
PHP | 539 lines | 214 code | 61 blank | 264 comment | 17 complexity | 891c0c98d933bdab030b60c617d15142 MD5 | raw file
  1. <?php
  2. /**
  3. * This file is part of the Adapto Toolkit.
  4. * Detailed copyright and licensing information can be found
  5. * in the doc/COPYRIGHT and doc/LICENSE files which should be
  6. * included in the distribution.
  7. *
  8. * @package adapto
  9. * @subpackage handlers
  10. *
  11. * @copyright (c)2000-2004 Ivo Jansch
  12. * @license http://www.achievo.org/atk/licensing ATK Open Source License
  13. *
  14. */
  15. /**
  16. * Some defines for return behaviour
  17. */
  18. define("Adapto_ACTION_STAY", 0);
  19. define("Adapto_ACTION_BACK", 1);
  20. /**
  21. * Generic action handler base class.
  22. *
  23. * Action handlers are responsible for performing actions on entitys (for
  24. * example "add", "edit", "delete", or any other custom actions your
  25. * application might have).
  26. * An action from the default handler can be overridden by implementing a
  27. * method in your entity with the name action_<actionname> where <actionname>
  28. * is the action you want to perform. The original handler is passed as a
  29. * parameter to the override.
  30. *
  31. * Custom action handlers should always be derived from Adapto_Handler_Action,
  32. * and should contain at least an implementation for the handle() method,
  33. * which is called by the framework to execute the action.
  34. *
  35. * @author ijansch
  36. * @package adapto
  37. * @subpackage handlers
  38. * @abstract
  39. */
  40. class Adapto_Handler_Action
  41. {
  42. /**
  43. * @var atkEntity
  44. * @access private
  45. */
  46. public $m_entity = NULL; // defaulted to public
  47. /** @access private */
  48. public $m_action = ""; // defaulted to public
  49. /** @access private */
  50. public $m_partial = NULL; // defaulted to public
  51. /** @access private */
  52. public $m_renderBoxVars = array(); // defaulted to public
  53. /** @access private */
  54. public $m_rejecting = false; // defaulted to public
  55. /** @access private */
  56. public $m_returnbehaviour = Adapto_ACTION_STAY; // defaulted to public
  57. /** @access protected */
  58. protected $m_boxTemplate = "box";
  59. /**
  60. * Render mode, defaults to "box" but can be changed to "dialog".
  61. *
  62. * @var string
  63. * @access protected
  64. */
  65. public $m_renderMode = 'box'; // defaulted to public
  66. /**
  67. * Default constructor.
  68. */
  69. public function __construct()
  70. {
  71. }
  72. /**
  73. * The handle() method handles the action.
  74. *
  75. * The default implementation invokes an action_$action override (if
  76. * present) and stores the postvars. Custom handlers may override this
  77. * behavior. If there is no entity action override and a partial is set
  78. * for the action we don't invoke the action_$action override but
  79. * instead let the partial method handle the action.
  80. *
  81. * @param atkEntity $entity The entity on which the action should be performed.
  82. * @param String $action The action that is being performed.
  83. * @param array $postvars Any variables from the request
  84. *
  85. */
  86. function handle(&$entity, $action, &$postvars)
  87. {
  88. $this->m_postvars = &$postvars;
  89. $this->m_entity = &$entity;
  90. $this->m_action = $action;
  91. $this->m_partial = $entity->m_partial;
  92. $this->invoke("action_" . $action);
  93. // when we're finished, cleanup any atkrejects (that we haven't set ourselves).
  94. if (!$this->m_rejecting) {
  95. Adapto_Util_Debugger::debug("clearing the stuff");
  96. $this->getRejectInfo(); // this will clear it.
  97. }
  98. }
  99. /**
  100. * Returns the entity object.
  101. *
  102. * @return atkEntity
  103. */
  104. public function getEntity()
  105. {
  106. return $this->m_entity;
  107. }
  108. /**
  109. * Get the reject info from the session
  110. * This is used by the atkAddHandler and atkEditHandler to
  111. * show the validation errors
  112. *
  113. * @return Array The reject info
  114. */
  115. function getRejectInfo()
  116. {
  117. return atkGetSessionManager()->stackVar('atkreject');
  118. }
  119. /**
  120. * Store the reject info in the session
  121. * This is used by the atkSaveHandler and atkUpdateHandler to
  122. * store the record if the record is not validated
  123. *
  124. * @param array $data The reject information
  125. */
  126. function setRejectInfo($data)
  127. {
  128. atkGetSessionManager()->stackVar('atkreject', $data, atkPrevLevel());
  129. $this->m_rejecting = true;
  130. }
  131. /**
  132. * Set the calling entity of the current action.
  133. * @param atkEntity $entity The entity on which the action should be performed.
  134. */
  135. function setEntity(&$entity)
  136. {
  137. $this->m_entity = &$entity;
  138. $this->m_partial = $entity->m_partial;
  139. $this->m_postvars = &$entity->m_postvars;
  140. }
  141. /**
  142. * Sets the current action.
  143. * @param string $action The action name.
  144. */
  145. function setAction($action)
  146. {
  147. $this->m_action = $action;
  148. }
  149. /**
  150. * Set postvars of the the calling entity of the current action.
  151. * @param array $postvars Postvars of the entity on which the action should be performed.
  152. */
  153. function setPostvars(&$postvars)
  154. {
  155. $this->m_postvars = &$postvars;
  156. }
  157. /**
  158. * Sets the render mode ("box" or "dialog").
  159. *
  160. * @param string $mode render mode
  161. */
  162. function setRenderMode($mode)
  163. {
  164. $this->m_renderMode = $mode;
  165. }
  166. /**
  167. * Returns the render mode.
  168. *
  169. * @return string render mode
  170. */
  171. function getRenderMode()
  172. {
  173. return $this->m_renderMode;
  174. }
  175. function setBoxTemplate($tpl)
  176. {
  177. $this->m_boxTemplate = $tpl;
  178. }
  179. /**
  180. * Get the page instance for generating output.
  181. *
  182. * @return atkPage The active page instance.
  183. */
  184. function &getPage()
  185. {
  186. return $this->m_entity->getPage();
  187. }
  188. /**
  189. * Get the ui instance for drawing and templating purposes.
  190. *
  191. * @return atkUi An atkUi instance for drawing and templating.
  192. */
  193. function &getUi()
  194. {
  195. return $this->m_entity->getUi();
  196. }
  197. /**
  198. * Generic method invoker.
  199. *
  200. * Handler methods invoked with invoke() instead of directly, have a major
  201. * advantage: the handler automatically searches for an override in the
  202. * entity. For example, If a handler calls its getSomething() method using
  203. * the invoke method, the entity may implement its own version of
  204. * getSomething() and that method will then be called instead of the
  205. * original. The handler is passed by reference to the override function
  206. * as first parameter, so if necessary, you can call the original method
  207. * from inside the override.
  208. *
  209. * The function accepts a variable number of parameters. Any parameter
  210. * that you would pass to the method, can be passed to invoke(), and
  211. * invoke() will pass the parameters on to the method.
  212. *
  213. * There is one limitation: you can't pass parameters by reference if
  214. * you use invoke().
  215. *
  216. * <b>Example:</b>
  217. *
  218. * <code>
  219. * $handler->invoke("editPage", $record, $mode);
  220. * </code>
  221. *
  222. * This will call editPage(&$handler, $record, $mode) on your entity class
  223. * if present, or editPage($record, $mode) in the handler if the entity has
  224. * no override.
  225. *
  226. * @param String $methodname The name of the method to call.
  227. * @return mixed The method returns the return value of the invoked
  228. * method.
  229. */
  230. function invoke($methodname)
  231. {
  232. $arguments = func_get_args(); // Put arguments in a variable (php won't let us pass func_get_args() to other functions directly.
  233. // the first argument is $methodname, which we already defined by name.
  234. array_shift($arguments);
  235. if ($this->m_entity !== NULL && method_exists($this->m_entity, $methodname)) {
  236. Adapto_Util_Debugger::debug("Invoking '$methodname' override on entity");
  237. // We pass the original object as first parameter to the override.
  238. array_unshift($arguments, $this);
  239. $arguments[0] = &$this; // reference copy workaround;
  240. return call_user_func_array(array(&$this->m_entity, $methodname), $arguments);
  241. } else if (method_exists($this, $methodname)) {
  242. Adapto_Util_Debugger::debug("Invoking '$methodname' on actionhandler for action " . $this->m_action);
  243. return call_user_func_array(array(&$this, $methodname), $arguments);
  244. }
  245. throw new Adapto_Exception("Undefined method '$methodname' in Adapto_Handler_Action");
  246. }
  247. /**
  248. * Static factory method to get the default action handler for a certain
  249. * action.
  250. *
  251. * When no action handler class can be found for the action, a default
  252. * handler is instantiated and returned. The default handler assumes that
  253. * the entity has an action_.... method, that will be called when the
  254. * actionhandler's handle() mehod is called.
  255. * @static
  256. *
  257. * @param String $action The action for which an action handler should be
  258. * retrieved.
  259. */
  260. function getDefaultHandler($action)
  261. {
  262. // The next if statement checks for 'known' actions. All unknown actions
  263. // are handled the backwardscompatible default way (invoking action_$action on the entity)
  264. $filename = Adapto_Config::getGlobal("atkroot") . "atk/handlers/class.atk" . $action . "handler.inc";
  265. if (file_exists($filename)) {
  266. return Adapto_ClassLoader::create("atk.handlers.atk" . $action . "handler");
  267. } else {
  268. // We don't have handlers yet for other actions.
  269. $actionhandler = new Adapto_Handler_Action(); // The default handler will automatically
  270. // invoke the entity methods.
  271. return $actionhandler;
  272. }
  273. }
  274. /**
  275. * Modify grid.
  276. *
  277. * @param atkDataGrid $grid grid
  278. * @param int $mode CREATE or RESUME
  279. */
  280. protected function modifyDataGrid(atkDataGrid $grid, $mode)
  281. {
  282. $method = 'modifyDataGrid';
  283. if (method_exists($this->getEntity(), $method)) {
  284. $this->getEntity()->$method($grid, $mode);
  285. }
  286. }
  287. /**
  288. * Get the cached recordlist
  289. *
  290. * @return atkRecordListCache object
  291. */
  292. function getRecordlistCache()
  293. {
  294. static $recordlistcache;
  295. if (!$recordlistcache) {
  296. $recordlistcache = &Adapto_ClassLoader::create("atk.recordlist.atkrecordlistcache");
  297. $recordlistcache->setEntity($this->m_entity);
  298. $recordlistcache->setPostvars($this->m_postvars);
  299. }
  300. return $recordlistcache;
  301. }
  302. /**
  303. * Clear the recordlist cache
  304. *
  305. */
  306. function clearCache()
  307. {
  308. if ($this->m_entity->hasFlag(EF_CACHE_RECORDLIST)) {
  309. $recordlistcache = $this->getRecordlistCache();
  310. if ($recordlistcache)
  311. $recordlistcache->clearCache($this->m_entity->atkEntityType());
  312. }
  313. }
  314. /**
  315. * Notify the entity that an action has occured
  316. *
  317. * @param string $action The action that occurred
  318. * @param array $record The record on which the action was performed
  319. */
  320. function notify($action, $record)
  321. {
  322. $this->m_entity->notify($action, $record);
  323. }
  324. /**
  325. * Add a variable to the renderbox
  326. *
  327. * @param string $key
  328. * @param string $value
  329. */
  330. function addRenderBoxVar($key, $value)
  331. {
  332. $this->m_renderBoxVars[$key] = $value;
  333. }
  334. /**
  335. * Set the returnbehaviour of this action
  336. *
  337. * @param Integer $returnbehaviour The return behaviour (possible values: Adapto_ACTION_BACK and Adapto_ACTION_STAY)
  338. */
  339. function setReturnBehaviour($returnbehaviour)
  340. {
  341. $this->m_returnbehaviour = $returnbehaviour;
  342. }
  343. /**
  344. * Get the returnbehaviour of this action
  345. *
  346. * @return String the return behaviour
  347. */
  348. function getReturnBehaviour()
  349. {
  350. return $this->m_returnbehaviour;
  351. }
  352. /**
  353. * Current action allowed on the given record?
  354. *
  355. * @param array $record record
  356. * @return boolean is action allowed on record?
  357. */
  358. function allowed($record)
  359. {
  360. return $this->m_entity->allowed($this->m_action, $record);
  361. }
  362. /**
  363. * Render access denied page.
  364. */
  365. function renderAccessDeniedPage()
  366. {
  367. $page = &$this->m_entity->getPage();
  368. $page->addContent($this->_getAccessDeniedPage());
  369. }
  370. /**
  371. * Get the access denied page
  372. *
  373. * @return String the HTML code of the access denied page
  374. */
  375. function _getAccessDeniedPage()
  376. {
  377. $controller = &atkController::getInstance();
  378. $controller->setEntity($this->m_entity);
  379. return $controller->accessDeniedPage();
  380. }
  381. /**
  382. * Render access denied dialog contents.
  383. *
  384. * @return String The access denied page in a dialog
  385. */
  386. function renderAccessDeniedDialog()
  387. {
  388. $message = $this->m_entity->text('access_denied') . "<br><br>" . $this->m_entity->text("error_entity_action_access_denied");
  389. return $this->renderMessageDialog($message);
  390. }
  391. /**
  392. * Render message dialog contents.
  393. *
  394. * @param String $message The message to render in a dialog
  395. * @return String The message dialog
  396. */
  397. function renderMessageDialog($message)
  398. {
  399. $ui = &$this->m_entity->getUi();
  400. $params = array();
  401. $params["content"] = "<br />" . $message . "<br />";
  402. $params["buttons"][] = '<input type="button" class="btn_cancel" value="' . $this->m_entity->text('close') . '" onClick="' . atkDialog::getCloseCall()
  403. . '" />';
  404. $content = $ui->renderAction($this->m_action, $params);
  405. $params = array();
  406. $params["title"] = $this->m_entity->actionTitle($this->m_action);
  407. $params["content"] = $content;
  408. $content = $ui->renderDialog($params);
  409. return $content;
  410. }
  411. /**
  412. * Outputs JavaScript for updating the existing dialog contents.
  413. *
  414. * @param string $content
  415. */
  416. function updateDialog($content)
  417. {
  418. $script = atkDialog::getUpdateCall($content, false);
  419. $page = &$this->getPage();
  420. $page->register_loadscript($script);
  421. }
  422. /**
  423. * Output JavaScript to close the dialog.
  424. */
  425. function closeDialog()
  426. {
  427. $script = atkDialog::getCloseCall();
  428. $page = &$this->getPage();
  429. $page->register_loadscript($script);
  430. }
  431. /**
  432. * Handle partial.
  433. *
  434. * @param string $partial full partial
  435. */
  436. function partial($partial)
  437. {
  438. $parts = explode(".", $partial);
  439. $method = "partial_" . $parts[0];
  440. if (!method_exists($this, $method)) {
  441. $content = '<span style="color: red; font-weight: bold">Invalid partial \'' . $this->m_partial . '\'!</span>';
  442. } else {
  443. $content = $this->$method($partial);
  444. }
  445. $page = &$this->getPage();
  446. $page->addContent($content);
  447. }
  448. /**
  449. * Get/generate CSRF token for the current session stack.
  450. *
  451. * http://www.owasp.org/index.php/Cross-Site_Request_Forgery_%28CSRF%29_Prevention_Cheat_Sheet
  452. *
  453. * @return string CSRF token
  454. */
  455. public function getCSRFToken()
  456. {
  457. // retrieve earlier generated token from the session stack
  458. $token = atkGetSessionManager()->globalStackVar('Adapto_CSRF_TOKEN');
  459. if ($token != null) {
  460. return $token;
  461. }
  462. // generate and store token in sesion stack
  463. $token = md5(uniqid(rand(), true));
  464. atkGetSessionManager()->globalStackVar('Adapto_CSRF_TOKEN', $token);
  465. return $token;
  466. }
  467. /**
  468. * Checks whatever the given CSRF token matches the one stored in the
  469. * session stack.
  470. *
  471. * @return boolean is valid CSRF token?
  472. */
  473. protected function isValidCSRFToken($token)
  474. {
  475. return $this->getCSRFToken() == $token;
  476. }
  477. }