|
|
@@ -0,0 +1,244 @@
|
|
|
+<?php
|
|
|
+/**
|
|
|
+ * MINZ - Copyright 2011 Marien Fressinaud
|
|
|
+ * Sous licence AGPL3 <http://www.gnu.org/licenses/>
|
|
|
+*/
|
|
|
+
|
|
|
+/**
|
|
|
+ * La classe Router gère le routage de l'application
|
|
|
+ * Les routes sont définies dans APP_PATH.'/configuration/routes.php'
|
|
|
+ */
|
|
|
+class Router {
|
|
|
+ const ROUTES_PATH_NAME = '/configuration/routes.php';
|
|
|
+
|
|
|
+ private $routes = array ();
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Constructeur
|
|
|
+ * @exception FileNotExistException si ROUTES_PATH_NAME n'existe pas
|
|
|
+ * et que l'on utilise l'url rewriting
|
|
|
+ */
|
|
|
+ public function __construct () {
|
|
|
+ if (Configuration::useUrlRewriting ()) {
|
|
|
+ if (file_exists (APP_PATH . self::ROUTES_PATH_NAME)) {
|
|
|
+ $routes = include (
|
|
|
+ APP_PATH . self::ROUTES_PATH_NAME
|
|
|
+ );
|
|
|
+
|
|
|
+ if (!is_array ($routes)) {
|
|
|
+ $routes = array ();
|
|
|
+ }
|
|
|
+
|
|
|
+ $this->routes = array_map (
|
|
|
+ array ('Url', 'checkUrl'),
|
|
|
+ $routes
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ throw new FileNotExistException (
|
|
|
+ self::ROUTES_PATH_NAME,
|
|
|
+ MinzException::ERROR
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Initialise le Router en déterminant le couple Controller / Action
|
|
|
+ * Mets à jour la Request
|
|
|
+ * @exception RouteNotFoundException si l'uri n'est pas présente dans
|
|
|
+ * > la table de routage
|
|
|
+ */
|
|
|
+ public function init () {
|
|
|
+ $url = array ();
|
|
|
+
|
|
|
+ if (Configuration::useUrlRewriting ()) {
|
|
|
+ try {
|
|
|
+ $url = $this->buildWithRewriting ();
|
|
|
+ } catch (RouteNotFoundException $e) {
|
|
|
+ throw $e;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ $url = $this->buildWithoutRewriting ();
|
|
|
+ }
|
|
|
+
|
|
|
+ $url['params'] = array_merge (
|
|
|
+ $url['params'],
|
|
|
+ Request::fetchPOST ()
|
|
|
+ );
|
|
|
+
|
|
|
+ Request::forward ($url);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Retourne un tableau représentant l'url passée par la barre d'adresses
|
|
|
+ * Ne se base PAS sur la table de routage
|
|
|
+ * @return tableau représentant l'url
|
|
|
+ */
|
|
|
+ public function buildWithoutRewriting () {
|
|
|
+ $url = array ();
|
|
|
+
|
|
|
+ $url['c'] = Request::fetchGET (
|
|
|
+ 'c',
|
|
|
+ Request::defaultControllerName ()
|
|
|
+ );
|
|
|
+ $url['a'] = Request::fetchGET (
|
|
|
+ 'a',
|
|
|
+ Request::defaultActionName ()
|
|
|
+ );
|
|
|
+ $url['params'] = Request::fetchGET ();
|
|
|
+
|
|
|
+ // post-traitement
|
|
|
+ unset ($url['params']['c']);
|
|
|
+ unset ($url['params']['a']);
|
|
|
+
|
|
|
+ return $url;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Retourne un tableau représentant l'url passée par la barre d'adresses
|
|
|
+ * Se base sur la table de routage
|
|
|
+ * @return tableau représentant l'url
|
|
|
+ * @exception RouteNotFoundException si l'uri n'est pas présente dans
|
|
|
+ * > la table de routage
|
|
|
+ */
|
|
|
+ public function buildWithRewriting () {
|
|
|
+ $url = array ();
|
|
|
+ $uri = Request::getURI ();
|
|
|
+ $find = false;
|
|
|
+
|
|
|
+ foreach ($this->routes as $route) {
|
|
|
+ $regex = '*^' . $route['route'] . '$*';
|
|
|
+ if (preg_match ($regex, $uri, $matches)) {
|
|
|
+ $url['c'] = $route['controller'];
|
|
|
+ $url['a'] = $route['action'];
|
|
|
+ $url['params'] = $this->getParams (
|
|
|
+ $route['params'],
|
|
|
+ $matches
|
|
|
+ );
|
|
|
+ $find = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!$find && $uri != '/') {
|
|
|
+ throw new RouteNotFoundException (
|
|
|
+ $uri,
|
|
|
+ MinzException::ERROR
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ // post-traitement
|
|
|
+ $url = Url::checkUrl ($url);
|
|
|
+
|
|
|
+ return $url;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Retourne l'uri d'une url en se basant sur la table de routage
|
|
|
+ * @param l'url sous forme de tableau
|
|
|
+ * @return l'uri formatée (string) selon une route trouvée
|
|
|
+ */
|
|
|
+ public function printUriRewrited ($url) {
|
|
|
+ $route = $this->searchRoute ($url);
|
|
|
+
|
|
|
+ if ($route !== false) {
|
|
|
+ return $this->replaceParams ($route, $url);
|
|
|
+ }
|
|
|
+
|
|
|
+ return '';
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Recherche la route correspondante à une url
|
|
|
+ * @param l'url sous forme de tableau
|
|
|
+ * @return la route telle que spécifiée dans la table de routage,
|
|
|
+ * false si pas trouvée
|
|
|
+ */
|
|
|
+ public function searchRoute ($url) {
|
|
|
+ foreach ($this->routes as $route) {
|
|
|
+ if ($route['controller'] == $url['c']
|
|
|
+ && $route['action'] == $url['a']) {
|
|
|
+ // calcule la différence des tableaux de params
|
|
|
+ $params = array_flip ($route['params']);
|
|
|
+ $difference_params = array_diff_key (
|
|
|
+ $params,
|
|
|
+ $url['params']
|
|
|
+ );
|
|
|
+
|
|
|
+ // vérifie que pas de différence
|
|
|
+ // et le cas où $params est vide et pas $url['params']
|
|
|
+ if (empty ($difference_params)
|
|
|
+ && (!empty ($params) || empty ($url['params']))) {
|
|
|
+ return $route;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Récupère un tableau dont
|
|
|
+ * - les clés sont définies dans $params_route
|
|
|
+ * - les valeurs sont situées dans $matches
|
|
|
+ * Le tableau $matches est décalé de +1 par rapport à $params_route
|
|
|
+ */
|
|
|
+ private function getParams($params_route, $matches) {
|
|
|
+ $params = array ();
|
|
|
+
|
|
|
+ for ($i = 0; $i < count ($params_route); $i++) {
|
|
|
+ $param = $params_route[$i];
|
|
|
+ $params[$param] = $matches[$i + 1];
|
|
|
+ }
|
|
|
+
|
|
|
+ return $params;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Remplace les éléments de la route par les valeurs contenues dans $url
|
|
|
+ * TODO Fonction très sale ! À revoir (preg_replace ?)
|
|
|
+ */
|
|
|
+ private function replaceParams ($route, $url) {
|
|
|
+ $uri = '';
|
|
|
+ $in_brackets = false;
|
|
|
+ $backslash = false;
|
|
|
+ $num_param = 0;
|
|
|
+
|
|
|
+ // parcourt caractère par caractère
|
|
|
+ for ($i = 0; $i < strlen ($route['route']); $i++) {
|
|
|
+ // on détecte qu'on rentre dans des parenthèses
|
|
|
+ // on va devoir changer par la valeur d'un paramètre
|
|
|
+ if ($route['route'][$i] == '(' && !$backslash) {
|
|
|
+ $in_brackets = true;
|
|
|
+ }
|
|
|
+ // on sort des parenthèses
|
|
|
+ // ok, on change le paramètre maintenant
|
|
|
+ if ($route['route'][$i] == ')' && !$backslash) {
|
|
|
+ $in_brackets = false;
|
|
|
+ $param = $route['params'][$num_param];
|
|
|
+ $uri .= $url['params'][$param];
|
|
|
+ $num_param++;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!$in_brackets
|
|
|
+ && ($route['route'][$i] != '\\' || $backslash)
|
|
|
+ && ($route['route'][$i] != '(' || $backslash)
|
|
|
+ && ($route['route'][$i] != ')' || $backslash)
|
|
|
+ && ($route['route'][$i] != '?' || $backslash)) {
|
|
|
+ // on est pas dans les parenthèses
|
|
|
+ // on recopie simplement le caractère
|
|
|
+ $uri .= $route['route'][$i];
|
|
|
+ }
|
|
|
+
|
|
|
+ // on détecte un backslash, on n'en veut pas
|
|
|
+ // sauf si on en avait déjà un juste avant
|
|
|
+ if ($route['route'][$i] == '\\' && !$backslash) {
|
|
|
+ $backslash = true;
|
|
|
+ } else {
|
|
|
+ $backslash = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return $uri;
|
|
|
+ }
|
|
|
+}
|