Router.php 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. <?php
  2. /**
  3. * MINZ - Copyright 2011 Marien Fressinaud
  4. * Sous licence AGPL3 <http://www.gnu.org/licenses/>
  5. */
  6. /**
  7. * La classe Router gère le routage de l'application
  8. * Les routes sont définies dans APP_PATH.'/configuration/routes.php'
  9. */
  10. class Router {
  11. const ROUTES_PATH_NAME = '/configuration/routes.php';
  12. private $routes = array ();
  13. /**
  14. * Constructeur
  15. * @exception FileNotExistException si ROUTES_PATH_NAME n'existe pas
  16. * et que l'on utilise l'url rewriting
  17. */
  18. public function __construct () {
  19. if (Configuration::useUrlRewriting ()) {
  20. if (file_exists (APP_PATH . self::ROUTES_PATH_NAME)) {
  21. $routes = include (
  22. APP_PATH . self::ROUTES_PATH_NAME
  23. );
  24. if (!is_array ($routes)) {
  25. $routes = array ();
  26. }
  27. $this->routes = array_map (
  28. array ('Url', 'checkUrl'),
  29. $routes
  30. );
  31. } else {
  32. throw new FileNotExistException (
  33. self::ROUTES_PATH_NAME,
  34. MinzException::ERROR
  35. );
  36. }
  37. }
  38. }
  39. /**
  40. * Initialise le Router en déterminant le couple Controller / Action
  41. * Mets à jour la Request
  42. * @exception RouteNotFoundException si l'uri n'est pas présente dans
  43. * > la table de routage
  44. */
  45. public function init () {
  46. $url = array ();
  47. if (Configuration::useUrlRewriting ()) {
  48. try {
  49. $url = $this->buildWithRewriting ();
  50. } catch (RouteNotFoundException $e) {
  51. throw $e;
  52. }
  53. } else {
  54. $url = $this->buildWithoutRewriting ();
  55. }
  56. $url['params'] = array_merge (
  57. $url['params'],
  58. Request::fetchPOST ()
  59. );
  60. Request::forward ($url);
  61. }
  62. /**
  63. * Retourne un tableau représentant l'url passée par la barre d'adresses
  64. * Ne se base PAS sur la table de routage
  65. * @return tableau représentant l'url
  66. */
  67. public function buildWithoutRewriting () {
  68. $url = array ();
  69. $url['c'] = Request::fetchGET (
  70. 'c',
  71. Request::defaultControllerName ()
  72. );
  73. $url['a'] = Request::fetchGET (
  74. 'a',
  75. Request::defaultActionName ()
  76. );
  77. $url['params'] = Request::fetchGET ();
  78. // post-traitement
  79. unset ($url['params']['c']);
  80. unset ($url['params']['a']);
  81. return $url;
  82. }
  83. /**
  84. * Retourne un tableau représentant l'url passée par la barre d'adresses
  85. * Se base sur la table de routage
  86. * @return tableau représentant l'url
  87. * @exception RouteNotFoundException si l'uri n'est pas présente dans
  88. * > la table de routage
  89. */
  90. public function buildWithRewriting () {
  91. $url = array ();
  92. $uri = Request::getURI ();
  93. $find = false;
  94. foreach ($this->routes as $route) {
  95. $regex = '*^' . $route['route'] . '$*';
  96. if (preg_match ($regex, $uri, $matches)) {
  97. $url['c'] = $route['controller'];
  98. $url['a'] = $route['action'];
  99. $url['params'] = $this->getParams (
  100. $route['params'],
  101. $matches
  102. );
  103. $find = true;
  104. break;
  105. }
  106. }
  107. if (!$find && $uri != '/') {
  108. throw new RouteNotFoundException (
  109. $uri,
  110. MinzException::ERROR
  111. );
  112. }
  113. // post-traitement
  114. $url = Url::checkUrl ($url);
  115. return $url;
  116. }
  117. /**
  118. * Retourne l'uri d'une url en se basant sur la table de routage
  119. * @param l'url sous forme de tableau
  120. * @return l'uri formatée (string) selon une route trouvée
  121. */
  122. public function printUriRewrited ($url) {
  123. $route = $this->searchRoute ($url);
  124. if ($route !== false) {
  125. return $this->replaceParams ($route, $url);
  126. }
  127. return '';
  128. }
  129. /**
  130. * Recherche la route correspondante à une url
  131. * @param l'url sous forme de tableau
  132. * @return la route telle que spécifiée dans la table de routage,
  133. * false si pas trouvée
  134. */
  135. public function searchRoute ($url) {
  136. foreach ($this->routes as $route) {
  137. if ($route['controller'] == $url['c']
  138. && $route['action'] == $url['a']) {
  139. // calcule la différence des tableaux de params
  140. $params = array_flip ($route['params']);
  141. $difference_params = array_diff_key (
  142. $params,
  143. $url['params']
  144. );
  145. // vérifie que pas de différence
  146. // et le cas où $params est vide et pas $url['params']
  147. if (empty ($difference_params)
  148. && (!empty ($params) || empty ($url['params']))) {
  149. return $route;
  150. }
  151. }
  152. }
  153. return false;
  154. }
  155. /**
  156. * Récupère un tableau dont
  157. * - les clés sont définies dans $params_route
  158. * - les valeurs sont situées dans $matches
  159. * Le tableau $matches est décalé de +1 par rapport à $params_route
  160. */
  161. private function getParams($params_route, $matches) {
  162. $params = array ();
  163. for ($i = 0; $i < count ($params_route); $i++) {
  164. $param = $params_route[$i];
  165. $params[$param] = $matches[$i + 1];
  166. }
  167. return $params;
  168. }
  169. /**
  170. * Remplace les éléments de la route par les valeurs contenues dans $url
  171. * TODO Fonction très sale ! À revoir (preg_replace ?)
  172. */
  173. private function replaceParams ($route, $url) {
  174. $uri = '';
  175. $in_brackets = false;
  176. $backslash = false;
  177. $num_param = 0;
  178. // parcourt caractère par caractère
  179. for ($i = 0; $i < strlen ($route['route']); $i++) {
  180. // on détecte qu'on rentre dans des parenthèses
  181. // on va devoir changer par la valeur d'un paramètre
  182. if ($route['route'][$i] == '(' && !$backslash) {
  183. $in_brackets = true;
  184. }
  185. // on sort des parenthèses
  186. // ok, on change le paramètre maintenant
  187. if ($route['route'][$i] == ')' && !$backslash) {
  188. $in_brackets = false;
  189. $param = $route['params'][$num_param];
  190. $uri .= $url['params'][$param];
  191. $num_param++;
  192. }
  193. if (!$in_brackets
  194. && ($route['route'][$i] != '\\' || $backslash)
  195. && ($route['route'][$i] != '(' || $backslash)
  196. && ($route['route'][$i] != ')' || $backslash)
  197. && ($route['route'][$i] != '?' || $backslash)) {
  198. // on est pas dans les parenthèses
  199. // on recopie simplement le caractère
  200. $uri .= $route['route'][$i];
  201. }
  202. // on détecte un backslash, on n'en veut pas
  203. // sauf si on en avait déjà un juste avant
  204. if ($route['route'][$i] == '\\' && !$backslash) {
  205. $backslash = true;
  206. } else {
  207. $backslash = false;
  208. }
  209. }
  210. return $uri;
  211. }
  212. }