AbstractRouter.php 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. <?php
  2. /**
  3. *
  4. * Cube Framework $Id$ erTeSBqvsjUzzNrXF38WCjSgLuhf+ktH/6TFC9LizWE=
  5. *
  6. * @link http://codecu.be/framework
  7. * @copyright Copyright (c) 2017 CodeCube SRL
  8. * @license http://codecu.be/framework/license Commercial License
  9. *
  10. * @version 1.9 [rev.1.9.01]
  11. */
  12. /**
  13. * routes management abstract class
  14. */
  15. namespace Cube\Controller\Router;
  16. use Cube\Controller\Request\AbstractRequest,
  17. Cube\Controller\Router\Route\RouteInterface,
  18. Cube\Controller\Front;
  19. abstract class AbstractRouter
  20. {
  21. const URI_DELIMITER = '/';
  22. const DEFAULT_CONTROLLER = 'Index';
  23. const DEFAULT_ACTION = 'Index';
  24. /**
  25. *
  26. * defined routes
  27. *
  28. * @var array
  29. */
  30. protected $_routes = array();
  31. /**
  32. *
  33. * the request object (containing only request params)
  34. *
  35. * @var \Cube\Controller\Request
  36. */
  37. protected $_request;
  38. /**
  39. *
  40. * the route class that corresponds to this router
  41. * defined in each class that extends this one
  42. *
  43. * @var string
  44. */
  45. protected $_routeClass;
  46. /**
  47. *
  48. * cache object
  49. *
  50. * @var \Cube\Cache|false false if caching is disabled in the application
  51. */
  52. protected $_cache = false;
  53. /**
  54. *
  55. * class constructor
  56. *
  57. * @param array $routes
  58. */
  59. public function __construct(array $routes = array())
  60. {
  61. $this->_cache = Front::getInstance()->getBootstrap()->getResource('cache');
  62. if (!empty($routes)) {
  63. $this->addRoutes($routes);
  64. }
  65. }
  66. /**
  67. *
  68. * add a single route to the routes array
  69. *
  70. * @param array|\Cube\Controller\Router\Route\RouteInterface $route can be an array from the config array or an instance of RouteInterface
  71. *
  72. * @return $this
  73. * @throws \BadMethodCallException
  74. */
  75. public function addRoute($route)
  76. {
  77. if ($route instanceof RouteInterface) {
  78. $this->_routes[] = $route;
  79. }
  80. else if (is_array($route)) {
  81. $route = $this->_setRouteFromArray($route);
  82. if ($route !== false) {
  83. $this->_routes[] = $route;
  84. }
  85. }
  86. else {
  87. throw new \BadMethodCallException('The route object must be an instance of Cube\Controller\Router\Route\AbstractRoute or an array');
  88. }
  89. return $this;
  90. }
  91. /**
  92. *
  93. * add multiple routes to the routes array
  94. *
  95. * @param array $routes
  96. *
  97. * @return $this
  98. */
  99. public function addRoutes(array $routes)
  100. {
  101. foreach ($routes as $route) {
  102. $this->addRoute($route);
  103. }
  104. return $this;
  105. }
  106. /**
  107. *
  108. * retrieve the routes array
  109. *
  110. * @return array
  111. */
  112. public function getRoutes()
  113. {
  114. return $this->_routes;
  115. }
  116. /**
  117. *
  118. * get a route object by its name
  119. *
  120. * @param string $name
  121. *
  122. * @return \Cube\Controller\Router\Route\RouteInterface
  123. * @throws \OutOfBoundsException
  124. */
  125. public function getRoute($name)
  126. {
  127. foreach ($this->_routes as $route) {
  128. /** @var \Cube\Controller\Router\Route\AbstractRoute $route */
  129. if ($route->getName() == $name) {
  130. return $route;
  131. }
  132. }
  133. throw new \OutOfBoundsException(
  134. sprintf("The route named '%s' does not exist.", $name));
  135. }
  136. /**
  137. *
  138. * set a routed request
  139. *
  140. * @param \Cube\Controller\Request\AbstractRequest $request
  141. *
  142. * @return $this
  143. */
  144. public function setRequest(AbstractRequest $request)
  145. {
  146. $this->_request = $this->route($request);
  147. return $this;
  148. }
  149. /**
  150. *
  151. * get routed request
  152. *
  153. * @return \Cube\Controller\Request
  154. */
  155. public function getRequest()
  156. {
  157. if (!$this->_request instanceof AbstractRequest) {
  158. $this->setRequest(
  159. new \Cube\Controller\Request());
  160. }
  161. return $this->_request;
  162. }
  163. /**
  164. *
  165. * create a route object from an input array
  166. *
  167. * @param array $route the route in array format
  168. *
  169. * @return \Cube\Controller\Router\Route\AbstractRoute|false return a route object or false if invalid data was provided
  170. */
  171. protected function _setRouteFromArray(array $route)
  172. {
  173. if (!empty($route[0])) {
  174. return new $this->_routeClass($route[0], $route[1], $route[2]);
  175. }
  176. return false;
  177. }
  178. /**
  179. *
  180. * route the request using a hardcoded default route
  181. *
  182. * the uri of the route is [/:module][/:controller][/:action][{/:paramKey/:paramValue}]
  183. *
  184. * @param \Cube\Controller\Request\AbstractRequest $request
  185. *
  186. * @return \Cube\Controller\Request\AbstractRequest
  187. */
  188. protected function _getDefaultRoute(AbstractRequest $request)
  189. {
  190. $parts = (array)$request->filterInput(array_filter(
  191. explode(self::URI_DELIMITER, $request->getRequestUri())
  192. ));
  193. $modules = (array)Front::getInstance()->getOption('modules');
  194. $part = ucfirst(array_shift($parts));
  195. if (in_array($part, $modules)) {
  196. $request->setModule(strtolower($part));
  197. $controller = array_shift($parts);
  198. }
  199. else {
  200. $request->setModule($modules[0]);
  201. $controller = $part;
  202. }
  203. $request->setController(
  204. (!empty($controller)) ? strtolower($controller) : self::DEFAULT_CONTROLLER);
  205. $action = array_shift($parts);
  206. $request->setAction(
  207. (!empty($action)) ? $action : self::DEFAULT_ACTION);
  208. while ($key = array_shift($parts)) {
  209. $value = array_shift($parts);
  210. $request->setParam($key, $value)
  211. ->setQuery($key, $value);
  212. }
  213. return $request;
  214. }
  215. /**
  216. *
  217. * get all params from the current request uri
  218. *
  219. * @param array $params
  220. * @param bool $addGetParams whether to attach params resulted from a previous get operation to the url
  221. * @param array $skipParams an array of params to be omitted when constructing the url
  222. *
  223. * @return array
  224. */
  225. protected function _getDefaultParams(array $params = null, $addGetParams = false, array $skipParams = null)
  226. {
  227. $data = array();
  228. $this->setRequest(
  229. new \Cube\Controller\Request());
  230. $request = $this->getRequest();
  231. $modules = (array)Front::getInstance()->getOption('modules');
  232. $module = $request->normalize(
  233. (isset($params['module'])) ? $params['module'] : $request->getModule(), true);
  234. $defaultModule = $modules[0];
  235. if ($module != $defaultModule) {
  236. $data['module'] = $module;
  237. }
  238. $data['controller'] = $request->normalize(
  239. (isset($params['controller'])) ? $params['controller'] : $request->getController(), true);
  240. $data['action'] = $request->normalize(
  241. (isset($params['action'])) ? $params['action'] : $request->getAction(), true);
  242. if ($addGetParams === true) {
  243. $params = array_merge((array)$request->getQuery(), (array)$params);
  244. }
  245. foreach ((array)$params as $key => $value) {
  246. if (!in_array($key, array('module', 'controller', 'action')) && !empty($value)) {
  247. $data[$key] = $value;
  248. }
  249. }
  250. foreach ((array)$skipParams as $key) {
  251. if (array_key_exists($key, $data)) {
  252. unset($data[$key]);
  253. }
  254. }
  255. return $data;
  256. }
  257. /**
  258. *
  259. * get cache
  260. *
  261. * @param string $key
  262. *
  263. * @return mixed
  264. */
  265. protected function _getCache($key = null)
  266. {
  267. if ($this->_cache !== false) {
  268. if ($key === null) {
  269. return $this->_cache;
  270. }
  271. else {
  272. $methodName = 'get' . ucfirst($key);
  273. if (method_exists($this->_cache, $methodName)) {
  274. return $this->_cache->$methodName();
  275. }
  276. }
  277. }
  278. return false;
  279. }
  280. /**
  281. *
  282. * routes a request and returns the routed request object
  283. * can match multiple routes, and will return the one that was matched last
  284. *
  285. * from the route's defaults array
  286. *
  287. * @param \Cube\Controller\Request\AbstractRequest $request
  288. *
  289. * @return \Cube\Controller\Request\AbstractRequest returns the routed request
  290. */
  291. abstract public function route(AbstractRequest $request);
  292. /**
  293. *
  294. * return a url string after processing the params and matching them to one of the existing routes
  295. * if a string is given, return it unmodified
  296. * if no route is specified
  297. *
  298. * @param mixed $params
  299. * @param string $name the name of a specific route to use
  300. * @param bool $addBaseUrl flag to add the base url param to the assembled route
  301. * @param bool $addGetParams whether to attach params resulted from a previous get operation to the url
  302. * @param array $skipParams an array of params to be omitted when constructing the url
  303. *
  304. * @return string
  305. */
  306. abstract public function assemble($params, $name = null, $addBaseUrl = true, $addGetParams = false, array $skipParams = null);
  307. }