PageRenderTime 53ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/Sijax/Core_Sijax.php

https://github.com/spantaleev/sijax
PHP | 338 lines | 146 code | 49 blank | 143 comment | 18 complexity | 056f7dff2641bbdcc252d7fbeaa1f3cd MD5 | raw file
  1. <?php
  2. /**
  3. * This is the main Sijax class that takes care of,
  4. * registering callable functions, processing incoming data and dispatching calls.
  5. */
  6. final class Core_Sijax {
  7. const PARAM_REQUEST = 'sijax_rq';
  8. const PARAM_ARGS = 'sijax_args';
  9. const EVENT_BEFORE_PROCESSING = 'beforeProcessing';
  10. const EVENT_AFTER_PROCESSING = 'afterProcessing';
  11. const EVENT_INVALID_REQUEST = 'invalidRequest';
  12. const PARAM_CALLBACK = 'callback';
  13. const PARAM_RESPONSE_CLASS = 'responseClass';
  14. private static $_requestUri = null;
  15. private static $_jsonUri = null;
  16. private static $_registeredMethods = array();
  17. private static $_events = array();
  18. //Would contain the request data (usually $_POST)
  19. private static $_data = array();
  20. //Would store a cached version of the arguments to pass to the requested function
  21. private static $_requestArgs = null;
  22. /**
  23. * Sets the incoming data array.
  24. * This is usually $_POST or whatever the framework uses.
  25. *
  26. * @param array $data
  27. */
  28. public static function setData(array $data) {
  29. self::$_data = $data;
  30. }
  31. /**
  32. * Returns the incoming data array.
  33. */
  34. public static function getData() {
  35. return self::$_data;
  36. }
  37. /**
  38. * Tells Sijax the URI to submit ajax requests to.
  39. * If you don't pass a request URI, the current URI would be
  40. * detected and set automatically.
  41. *
  42. * @param string $uri
  43. */
  44. public static function setRequestUri($uri) {
  45. self::$_requestUri = $uri;
  46. }
  47. /**
  48. * Sets the URI to an external JSON library,
  49. * for browsers that do not support native JSON (such as IE<=7).
  50. *
  51. * The specified script will only be loaded if such a browser is detected.
  52. * If this is not specified, Sijax will not work at all in IE<=7.
  53. *
  54. * @param $uri
  55. */
  56. public static function setJsonUri($uri) {
  57. self::$_jsonUri = $uri;
  58. }
  59. /**
  60. * Returns the name of the requested function
  61. * or NULL if no function is requested.
  62. */
  63. public static function getRequestFunction() {
  64. if (! isset(self::$_data[self::PARAM_REQUEST])) {
  65. return null;
  66. }
  67. return (string) self::$_data[self::PARAM_REQUEST];
  68. }
  69. /**
  70. * Returns an array of arguments to pass to the requested function.
  71. */
  72. public static function getRequestArgs() {
  73. if (self::$_requestArgs === null) {
  74. if (isset(self::$_data[self::PARAM_ARGS])) {
  75. self::$_requestArgs = (array) json_decode(self::$_data[self::PARAM_ARGS], true);
  76. } else {
  77. self::$_requestArgs = array();
  78. }
  79. }
  80. return self::$_requestArgs;
  81. }
  82. /**
  83. * Sets the request arguments, possibly overriding the autodetected arguments array.
  84. * This is useful for plugins that would like to "rewrite" the arguments array.
  85. *
  86. * @param array $args
  87. */
  88. public static function setRequestArgs(array $args) {
  89. self::$_requestArgs = $args;
  90. }
  91. /**
  92. * Tells whether the current request is a Sijax request.
  93. */
  94. public static function isSijaxRequest() {
  95. if (! isset(self::$_data[self::PARAM_REQUEST])) {
  96. return false;
  97. }
  98. if (! isset(self::$_data[self::PARAM_ARGS])) {
  99. return false;
  100. }
  101. return true;
  102. }
  103. /**
  104. * Registers all methods of the specified object instance (or class).
  105. * These methods will be callable from the browser.
  106. *
  107. * The optional $params array allows the response class
  108. * to be changed from the default one (Core_Sijax_Response).
  109. *
  110. * @param object/class $object
  111. * @param array $params
  112. * @throws Exception
  113. */
  114. public static function registerObject($object, $params = array()) {
  115. if ($object === null) {
  116. throw new Exception ( 'Object is NULL!' );
  117. }
  118. foreach ( get_class_methods ( $object ) as $methodName ) {
  119. if (isset(self::$_registeredMethods[$methodName])) {
  120. //Don't register methods on top of another methods..
  121. continue;
  122. }
  123. $params [self::PARAM_CALLBACK] = array ( $object, $methodName );
  124. self::$_registeredMethods [$methodName] = $params;
  125. }
  126. }
  127. /**
  128. * Registers the specified callback function (closure, class method, function name),
  129. * to be callable from the browser.
  130. *
  131. * The optional $params array allows the response class
  132. * to be changed from the default one (Core_Sijax_Response).
  133. *
  134. * @param $functionName
  135. * @param $callback
  136. * @param $params
  137. */
  138. public static function registerCallback($functionName, $callback, $params = array()) {
  139. $params [self::PARAM_CALLBACK] = $callback;
  140. self::$_registeredMethods [$functionName] = $params;
  141. }
  142. /**
  143. * Executes the specified callback (closure, class method, function name),
  144. * passing the specified arguments to it.
  145. *
  146. * The optional $params array allows the response class
  147. * to be changed from the default one (Core_Sijax_Response).
  148. *
  149. * @param callback $callback
  150. * @param array $args
  151. * @param array $params
  152. */
  153. public static function executeCallback($callback = null, $args = array(), $params = array()) {
  154. if (isset($params [self::PARAM_RESPONSE_CLASS])) {
  155. $responseClass = $params [self::PARAM_RESPONSE_CLASS];
  156. } else {
  157. $responseClass = __CLASS__ . '_Response';
  158. }
  159. $objResponse = new $responseClass($args);
  160. self::fireEvent($objResponse, self::EVENT_BEFORE_PROCESSING, array());
  161. self::_callFunction($callback, $objResponse);
  162. self::fireEvent($objResponse, self::EVENT_AFTER_PROCESSING, array());
  163. die($objResponse->getJson());
  164. }
  165. /**
  166. * Inspects the data array (as specified by setData()) to determine
  167. * if the current server request is to be handled by sijax.
  168. *
  169. * If this is a normal page request, this simply returns without doing anything.
  170. *
  171. * If this is a VALID sijax request (for a registered function), it gets called.
  172. *
  173. * If this is an INVALID sijax request, the EVENT_INVALID_REQUEST event gets fired.
  174. * In case no custom event handler is specified, the default one is triggered (_invalidRequestCallback).
  175. */
  176. public static function processRequest() {
  177. if (! self::isSijaxRequest()) {
  178. return;
  179. }
  180. $requestFunction = self::getRequestFunction();
  181. $callback = null;
  182. $args = array();
  183. $params = array();
  184. if (isset(self::$_registeredMethods[$requestFunction])) {
  185. $params = self::$_registeredMethods[$requestFunction];
  186. $callback = $params [self::PARAM_CALLBACK];
  187. $args = self::getRequestArgs();
  188. } else {
  189. if (self::hasEvent(self::EVENT_INVALID_REQUEST)) {
  190. $callback = self::$_events[self::EVENT_INVALID_REQUEST];
  191. } else {
  192. $callback = array(__CLASS__, '_invalidRequestCallback');
  193. }
  194. $args = array($requestFunction);
  195. }
  196. self::executeCallback($callback, $args, $params);
  197. }
  198. private static function _invalidRequestCallback(Core_Sijax_Response $objResponse, $functionName) {
  199. $objResponse->alert('The action you performed is currently unavailable! (Sijax error)');
  200. }
  201. /**
  202. * Prepares the callback function arguments and calls it.
  203. *
  204. * The optional $requestArgs array allows the detected request args
  205. * which may have been altered by the response object to be overriden.
  206. * It's not used for normal requests.
  207. * Events and manually executed callbacks however override the request args.
  208. *
  209. * @param callback $callback
  210. * @param Core_Sijax_Response $objResponse
  211. * @param array $requestArgs
  212. */
  213. private static function _callFunction($callback, Core_Sijax_Response $objResponse, $requestArgs = null) {
  214. if ($requestArgs === null) {
  215. /**
  216. * Normal functions are called like this.
  217. * The object response class was given the args before,
  218. * but may have changed them
  219. */
  220. $requestArgs = $objResponse->getRequestArgs();
  221. }
  222. $args = array_merge(array($objResponse), $requestArgs);
  223. try {
  224. call_user_func_array($callback, $args);
  225. } catch (\TypeError $e) {
  226. $objResponse->call('console.log', ['Sijax error: function called with an invalid number of arguments or wrong types']);
  227. }
  228. }
  229. /**
  230. * Sets a callback function to be called when the specified event occurs.
  231. * Only one callback can be executed per event.
  232. *
  233. * The provided EVENT_* constants should be used for handling system events.
  234. * Additionally, you can use any string to define your own events and callbacks.
  235. *
  236. * If more are needed, they may be chained manually.
  237. * Certain functionality to allow this (getEvent()) is missing though.
  238. *
  239. * @param string $eventName
  240. * @param callback $callback
  241. */
  242. public static function registerEvent($eventName, $callback) {
  243. self::$_events[$eventName] = $callback;
  244. }
  245. /**
  246. * Tells whether there's a callback function to be called
  247. * when the specified event occurs.
  248. *
  249. * @param string $eventName
  250. */
  251. public static function hasEvent($eventName) {
  252. return isset(self::$_events[$eventName]);
  253. }
  254. /**
  255. * Fires the specified event.
  256. *
  257. * @param Core_Sijax_Response $objResponse
  258. * @param string $eventName
  259. * @param array $args
  260. */
  261. public static function fireEvent(Core_Sijax_Response $objResponse, $eventName, array $args) {
  262. if (! self::hasEvent($eventName)) {
  263. return;
  264. }
  265. return self::_callFunction(self::$_events[$eventName], $objResponse, $args);
  266. }
  267. /**
  268. * Tries to detect the current request URI.
  269. * Sijax requests would be send to the same URI.
  270. * If you want to avoid autodetection, or override this, use setRequestUri().
  271. */
  272. private static function _detectRequestUri() {
  273. $requestUri = strip_tags ( isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '');
  274. self::setRequestUri($requestUri);
  275. }
  276. /**
  277. * Returns the javascript needed to prepare sijax for running on a page.
  278. */
  279. public static function getJs() {
  280. if (self::$_requestUri === null) {
  281. self::_detectRequestUri();
  282. }
  283. $script = "";
  284. $script .= "Sijax.setRequestUri(" . json_encode(self::$_requestUri) . ");";
  285. $script .= "Sijax.setJsonUri(" . json_encode(self::$_jsonUri) . ");";
  286. return $script;
  287. }
  288. }
  289. ?>