PageRenderTime 49ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/src/EpiRoute.php

http://github.com/jmathai/epiphany
PHP | 262 lines | 142 code | 23 blank | 97 comment | 30 complexity | 637498c02f4314c57123be3431850011 MD5 | raw file
  1. <?php
  2. /**
  3. * EpiRoute master file
  4. *
  5. * This contains the EpiRoute class as wel as the EpiException abstract class
  6. * @author Jaisen Mathai <jaisen@jmathai.com>
  7. * @version 1.0
  8. * @package EpiRoute
  9. */
  10. /**
  11. * This is the EpiRoute class.
  12. * @name EpiRoute
  13. * @author Jaisen Mathai <jaisen@jmathai.com>
  14. * @final
  15. */
  16. class EpiRoute
  17. {
  18. private static $instance;
  19. private $routes = array();
  20. private $regexes= array();
  21. private $route = null;
  22. const routeKey= '__route__';
  23. const httpGet = 'GET';
  24. const httpPost= 'POST';
  25. const httpPut = 'PUT';
  26. const httpDelete = 'DELETE';
  27. /**
  28. * get('/', 'function');
  29. * @name get
  30. * @author Jaisen Mathai <jaisen@jmathai.com>
  31. * @param string $route
  32. * @param mixed $callback
  33. */
  34. public function get($route, $callback, $isApi = false)
  35. {
  36. $this->addRoute($route, $callback, self::httpGet, $isApi);
  37. }
  38. /**
  39. * post('/', 'function');
  40. * @name post
  41. * @author Jaisen Mathai <jaisen@jmathai.com>
  42. * @param string $route
  43. * @param mixed $callback
  44. */
  45. public function post($route, $callback, $isApi = false)
  46. {
  47. $this->addRoute($route, $callback, self::httpPost, $isApi);
  48. }
  49. /**
  50. * put('/', 'function');
  51. * @name put
  52. * @author Sandro Meier <sandro.meier@fidelisfactory.ch>
  53. * @param string $route
  54. * @param mixed $callback
  55. */
  56. public function put($route, $callback, $isApi = false)
  57. {
  58. $this->addRoute($route, $callback, self::httpPut, $isApi);
  59. }
  60. /**
  61. * delete('/', 'function');
  62. * @name delete
  63. * @author Sandro Meier <sandro.meier@fidelisfactory.ch>
  64. * @param string $route
  65. * @param mixed $callback
  66. */
  67. public function delete($route, $callback, $isApi = false)
  68. {
  69. $this->addRoute($route, $callback, self::httpDelete, $isApi);
  70. }
  71. /**
  72. * NOT YET IMPLEMENTED
  73. * request('/', 'function', array(EpiRoute::httpGet, EpiRoute::httpPost));
  74. * @name request
  75. * @author Jaisen Mathai <jaisen@jmathai.com>
  76. * @param string $route
  77. * @param mixed $callback
  78. */
  79. /*public function request($route, $callback, $httpMethods = array(self::httpGet, self::httpPost))
  80. {
  81. }*/
  82. /**
  83. * load('/path/to/file');
  84. * @name load
  85. * @author Jaisen Mathai <jaisen@jmathai.com>
  86. * @param string $file
  87. */
  88. public function load($file)
  89. {
  90. $file = Epi::getPath('config') . "/{$file}";
  91. if(!file_exists($file))
  92. {
  93. EpiException::raise(new EpiException("Config file ({$file}) does not exist"));
  94. break; // need to simulate same behavior if exceptions are turned off
  95. }
  96. $parsed_array = parse_ini_file($file, true);
  97. foreach($parsed_array as $route)
  98. {
  99. $method = strtolower($route['method']);
  100. if(isset($route['class']) && isset($route['function']))
  101. $this->$method($route['path'], array($route['class'], $route['function']));
  102. elseif(isset($route['function']))
  103. $this->$method($route['path'], $route['function']);
  104. }
  105. }
  106. /**
  107. * EpiRoute::run($_GET['__route__'], $_['routes']);
  108. * @name run
  109. * @author Jaisen Mathai <jaisen@jmathai.com>
  110. * @param string $route
  111. * @param array $routes
  112. * @method run
  113. * @static method
  114. */
  115. public function run($route = false, $httpMethod = null)
  116. {
  117. if($route === false)
  118. $route = isset($_GET[self::routeKey]) ? $_GET[self::routeKey] : '/';
  119. if($httpMethod === null)
  120. $httpMethod = $_SERVER['REQUEST_METHOD'];
  121. $routeDef = $this->getRoute($route, $httpMethod);
  122. $response = call_user_func_array($routeDef['callback'], $routeDef['args']);
  123. if(!$routeDef['postprocess'])
  124. return $response;
  125. else
  126. {
  127. // Only echo the response if it's not null.
  128. if (!is_null($response))
  129. {
  130. $response = json_encode($response);
  131. if(isset($_GET['callback']))
  132. $response = "{$_GET['callback']}($response)";
  133. else
  134. header('Content-Type: application/json');
  135. header('Content-Length:' . strlen($response));
  136. echo $response;
  137. }
  138. }
  139. }
  140. /**
  141. * EpiRoute::getRoute($route);
  142. * @name getRoute
  143. * @author Jaisen Mathai <jaisen@jmathai.com>
  144. * @param string $route
  145. * @method getRoute
  146. * @static method
  147. */
  148. public function getRoute($route = false, $httpMethod = null)
  149. {
  150. if($route)
  151. $this->route = $route;
  152. else
  153. $this->route = isset($_GET[self::routeKey]) ? $_GET[self::routeKey] : '/';
  154. if($httpMethod === null)
  155. $httpMethod = $_SERVER['REQUEST_METHOD'];
  156. foreach($this->regexes as $ind => $regex)
  157. {
  158. if(preg_match($regex, $this->route, $arguments))
  159. {
  160. array_shift($arguments);
  161. $def = $this->routes[$ind];
  162. if($httpMethod != $def['httpMethod'])
  163. {
  164. continue;
  165. }
  166. else if(is_array($def['callback']) && method_exists($def['callback'][0], $def['callback'][1]))
  167. {
  168. if(Epi::getSetting('debug'))
  169. getDebug()->addMessage(__CLASS__, sprintf('Matched %s : %s : %s : %s', $httpMethod, $this->route, json_encode($def['callback']), json_encode($arguments)));
  170. return array('callback' => $def['callback'], 'args' => $arguments, 'postprocess' => $def['postprocess']);
  171. }
  172. else if(function_exists($def['callback']))
  173. {
  174. if(Epi::getSetting('debug'))
  175. getDebug()->addMessage(__CLASS__, sprintf('Matched %s : %s : %s : %s', $httpMethod, $this->route, json_encode($def['callback']), json_encode($arguments)));
  176. return array('callback' => $def['callback'], 'args' => $arguments, 'postprocess' => $def['postprocess']);
  177. }
  178. EpiException::raise(new EpiException('Could not call ' . json_encode($def) . " for route {$regex}"));
  179. }
  180. }
  181. EpiException::raise(new EpiException("Could not find route {$this->route} from {$_SERVER['REQUEST_URI']}"));
  182. }
  183. /**
  184. * EpiRoute::redirect($url);
  185. * @name redirect
  186. * @author Jaisen Mathai <jaisen@jmathai.com>
  187. * @param string $url
  188. * @method redirect
  189. * @static method
  190. */
  191. public function redirect($url, $code = null, $offDomain = false)
  192. {
  193. $continue = !empty($url);
  194. if($offDomain === false && preg_match('#^https?://#', $url))
  195. $continue = false;
  196. if($continue)
  197. {
  198. if($code != null && (int)$code == $code)
  199. header("Status: {$code}");
  200. header("Location: {$url}");
  201. die();
  202. }
  203. EpiException::raise(new EpiException("Redirect to {$url} failed"));
  204. }
  205. public function route()
  206. {
  207. return $this->route;
  208. }
  209. /*
  210. * EpiRoute::getInstance
  211. */
  212. public static function getInstance()
  213. {
  214. if(self::$instance)
  215. return self::$instance;
  216. self::$instance = new EpiRoute;
  217. return self::$instance;
  218. }
  219. /**
  220. * addRoute('/', 'function', 'GET');
  221. * @name addRoute
  222. * @author Jaisen Mathai <jaisen@jmathai.com>
  223. * @param string $route
  224. * @param mixed $callback
  225. * @param mixed $method
  226. * @param string $callback
  227. */
  228. private function addRoute($route, $callback, $method, $postprocess = false)
  229. {
  230. $this->routes[] = array('httpMethod' => $method, 'path' => $route, 'callback' => $callback, 'postprocess' => $postprocess);
  231. $this->regexes[]= "#^{$route}\$#";
  232. if(Epi::getSetting('debug'))
  233. getDebug()->addMessage(__CLASS__, sprintf('Found %s : %s : %s', $method, $route, json_encode($callback)));
  234. }
  235. }
  236. function getRoute()
  237. {
  238. return EpiRoute::getInstance();
  239. }