2015-02-17 16:17:38 +01:00
< ? php
/**
* Cette classe gère l ' appel des ressources
*/
class Router
{
public $route ; //Route actuelle
public $controllerName ; //Nom du controleur obtenu depuis la route de création
public $methodName ; //Nom de la méthode obtenu depuis la route de création
public $params ; //Tableau des paramètres GET passé dans la route
public function __construct ( $route = '' )
{
if ( $route )
{
$this -> route = $route ;
$this -> controllerName = $this -> parseController ( $route );
$this -> methodName = $this -> parseMethod ( $route );
$this -> params = $this -> parseParams ( $route );
}
else
{
$this -> route = '' ;
$this -> controllerName = '' ;
$this -> methodName = '' ;
$this -> params = '' ;
}
}
//Getters et setters
public function getRoute ()
{
return $this -> route ;
}
public function setRoute ( $value )
{
$this -> route = $route ;
}
public function getControllerName ()
{
return $this -> controllerName ;
}
public function setControllerName ( $value )
{
$this -> controllerName = $value ;
}
public function getMethodName ()
{
return $this -> methodName ;
}
public function setMethodName ( $value )
{
$this -> methodName = $value ;
}
public function getParams ()
{
return $this -> params ;
}
public function setParams ( $value )
{
$this -> params = $value ;
}
2015-08-09 18:11:59 +02:00
/**
* Cette méthode retourne la page 404 par défaut
*/
public function return404 ()
{
http_response_code ( 404 );
include ( PWD . 'mvc/404.php' );
die ();
}
2015-02-17 16:17:38 +01:00
/**
* Retourne une route avec seulement l ' url parsée comme il faut
* @ param string $route : La route à analyser
* @ return array : Le tableau de la route parsée
*/
public function parseRoute ( $route )
{
$directory_to_remove = strstr ( preg_replace ( '#http(s)?://#' , '' , HTTP_PWD ), '/' ); //On retire la partie protocole, et l'adresse du serveur de la partie de la route à ignorer
$route = mb_strcut ( $route , mb_strlen ( $directory_to_remove )); //On retire la partie à ignorer de la route
2015-08-09 18:11:59 +02:00
$route = explode ( '?' , $route )[ 0 ]; //on ne garde que ce qui précède les arguments
$route = preg_split ( '#[/]#' , $route ); //On explose la route
2015-02-17 16:17:38 +01:00
foreach ( $route as $key => $val ) //On garde seulement les repertoires non vides
{
2015-08-09 18:11:59 +02:00
if ( empty ( $val ) && $val !== 0 && $val !== '0' )
2015-02-17 16:17:38 +01:00
{
unset ( $route [ $key ]);
}
}
$route = array_values ( $route ); //On remet à 0 les index pour obtenir un tableau propre
return $route ;
}
/**
* Retrouve le controlleur dans un URL
* @ param string $route : la route à analyser
* @ return string : Le nom du controleur
*/
public function parseController ( $route )
{
$route = $this -> parseRoute ( $route ); //On récupère la route parsé
2015-08-09 18:11:59 +02:00
//Si pas de controlleur, on prend celui par défaut
if ( empty ( $route [ 0 ]))
2015-02-17 16:17:38 +01:00
{
2015-08-09 18:11:59 +02:00
return DEFAULT_CONTROLLER ;
2015-02-17 16:17:38 +01:00
}
2015-08-09 18:11:59 +02:00
//Sinon, si le controlleur n'existe pas ou est internal, on retourne une 404
if ( ! file_exists ( PWD_CONTROLLER . $route [ 0 ] . '.php' ) || mb_strpos ( $route [ 0 ], 'internal' ) !== false )
2015-02-17 16:17:38 +01:00
{
2015-08-09 18:11:59 +02:00
return $this -> return404 ();
2015-02-17 16:17:38 +01:00
}
2015-08-09 18:11:59 +02:00
//On retourne le controlleur adapté
return $route [ 0 ];
2015-02-17 16:17:38 +01:00
}
/**
* Retrouve la méthode dans un URL
* @ param string $route : la route à analyser
* @ return string : Le nom de la methode
*/
public function parseMethod ( $route )
{
2015-08-09 18:11:59 +02:00
//On instancie le controlleur
2015-02-17 16:17:38 +01:00
$controllerName = $this -> parseController ( $route );
$controller = new $controllerName ();
2015-08-09 18:11:59 +02:00
$prefixMethod = '' ;
//On recupère les paramètres dans l'url pour les utiliser un peu plus tard
$params = $this -> parseParams ( $route );
//On vérifie si le controlleur est un controlleur API, si c'est le cas on le refais avec cette fois la bonne methode
if ( $controller instanceof ApiController )
{
//On va choisir le type à employer
$method = $_SERVER [ 'REQUEST_METHOD' ];
switch ( mb_convert_case ( $method , MB_CASE_LOWER ))
{
case 'delete' :
$prefixMethod = 'delete' ;
break ;
case 'patch' :
$prefixMethod = 'patch' ;
break ;
case 'post' :
$prefixMethod = 'post' ;
break ;
case 'put' :
$prefixMethod = 'put' ;
break ;
default :
$prefixMethod = 'get' ;
}
}
2015-02-17 16:17:38 +01:00
$route = $this -> parseRoute ( $route ); //On récupère la route parsé
2015-08-09 18:11:59 +02:00
//On regarde quelle route il nous faut et on evite les routes qui commencent par '_', qui sont maintenant considérées comme privées
if ( empty ( $route [ 1 ]))
{
$method = DEFAULT_METHOD ;
}
else
2015-02-17 16:17:38 +01:00
{
2015-08-09 18:11:59 +02:00
$method = $route [ 1 ];
2015-02-17 16:17:38 +01:00
}
2015-08-09 18:11:59 +02:00
if ( $prefixMethod )
2015-02-17 16:17:38 +01:00
{
2015-08-09 18:11:59 +02:00
$method = $prefixMethod . mb_convert_case ( $method , MB_CASE_TITLE );
2015-02-17 16:17:38 +01:00
}
2015-08-09 18:11:59 +02:00
//Si la méthode à appeler n'existe pas ou si la route commencent par '_', signe qu'elle est un outils non accessibles
if ( ! method_exists ( $controller , $method ) || mb_substr ( $method , 0 , 1 ) == '_' )
{
return $this -> return404 ();
}
//On instancie la classe reflection de PHP sur la méthode que l'on veux analyser pour l'objet controller
$methodAnalyser = new ReflectionMethod ( $controller , $method );
//Si la méthode à appeler demande plus de paramètres que fournis on retourne une 404
if ( $methodAnalyser -> getNumberOfRequiredParameters () > count ( $params ))
{
return $this -> return404 ();
}
2015-02-17 16:17:38 +01:00
return $method ;
}
/**
* Retrouve les paramètres dans un URL
* @ param string $route : la route à analyser
* @ return array : La liste des paramètres au format $clef => $valeur
*/
public function parseParams ( $route )
{
$route = $this -> parseRoute ( $route ); //On récupère la route parsé
$params = array ();
2015-08-09 18:11:59 +02:00
//On transforme les paramètres $_GET passés par l'url au format clef-value. Ex : prenom-pierre-lin = $_GET['prenom'] => 'pierre-lin'
2015-02-17 16:17:38 +01:00
if ( count ( $route ) > 2 ) //Si on a plus de deux paramètres qui ont été passé
{
unset ( $route [ 0 ], $route [ 1 ]); //On supprime le controlleur, et la route, des paramètres, il ne reste que les parametres a passer en GET
2015-08-09 18:11:59 +02:00
foreach ( $route as $param )
2015-02-17 16:17:38 +01:00
{
2015-08-09 18:11:59 +02:00
$params [] = rawurldecode ( $param );
2015-02-17 16:17:38 +01:00
}
}
return $params ;
}
2015-08-09 18:11:59 +02:00
/**
* Cette fonction permet de vérifier si le cache est activé pour une route , et si oui quel fichier utiliser
* @ param string $route : Route à analyser
* @ return mixed : Si pas de cache , faux . Sinon un tableau avec deux clefs , " state " => statut du nom de fichier retourné ( true , le fichier doit être utilisé , false , le fichier doit être créé ), " file " => Le nom du fcihier de cache
*/
public function verifyCache ( $route )
{
//On récupère le nom du controller et de la méthode
$controllerName = $this -> parseController ( $route );
$methodName = $this -> parseMethod ( $route );
$params = $this -> parseParams ( $route );
$controller = new $controllerName ();
//Si on ne doit pas activer le cache ou si on na pas de cache pour ce fichier
if ( ! ACTIVATING_CACHE || ! property_exists ( $controller , 'cache_' . $methodName ))
{
return false ;
}
//Si on a du cache, on va déterminer le nom approprié
//Format de nom = <hash:nom_router.nom_methode><hash_datas>
$hashName = md5 ( $controllerName . $methodName );
$hashDatas = md5 ( json_encode ( $_GET ) . json_encode ( $_POST ) . json_encode ( $params ));
$fileName = $hashName . $hashDatas ;
//Si il n'existe pas de fichier de cache pour ce fichier
if ( ! file_exists ( PWD_CACHE . $fileName ))
{
return array ( 'state' => false , 'file' => $fileName );
}
//Sinon, si le fichier de cache existe
$fileLastChange = filemtime ( PWD_CACHE . $fileName );
//On calcul la date de mise à jour valide la plus ancienne possible
$now = new DateTime ();
$propertyName = 'cache_' . $methodName ;
$propertyValue = $controller -> $propertyName ;
$now -> sub ( new DateInterval ( 'PT' . $propertyValue . 'M' ));
$maxDate = $now -> format ( 'U' );
//Si le fichier de cache est trop vieux
if ( $fileLastChange < $maxDate )
{
return array ( 'state' => false , 'file' => $fileName );
}
//Sinon, on retourne le fichier de cache en disant de l'utiliser
return array ( 'state' => true , 'file' => $fileName );
}
2015-02-17 16:17:38 +01:00
/**
* Cette fonction permet de charger la page adaptée a partir d ' une url
2015-08-09 18:11:59 +02:00
* Elle gère également le cache
2015-02-17 16:17:38 +01:00
* @ param string $route : Route à analyser pour charger une page
* @ return void
*/
public function loadRoute ( $route )
{
2015-08-09 18:11:59 +02:00
$params = $this -> parseParams ( $route ); //On récupère les paramètres à passer à la fonction
2015-02-17 16:17:38 +01:00
$controllerName = $this -> parseController ( $route ); //On récupère le nom du controleur à appeler
$controller = new $controllerName (); //On créer le controleur
2015-08-09 18:11:59 +02:00
2015-02-17 16:17:38 +01:00
$beforeMethodName = DEFAULT_BEFORE ; //On défini le nom de la fonction before
if ( method_exists ( $controller , $beforeMethodName )) //Si une fonction before existe pour ce controller, on l'appel
{
$controller -> $beforeMethodName (); //On appel la fonction before
}
$methodName = $this -> parseMethod ( $route ); //On récupère le nom de la méthode
2015-08-09 18:11:59 +02:00
$verifyCache = $this -> verifyCache ( $route );
2015-02-17 16:17:38 +01:00
2015-08-09 18:11:59 +02:00
//Si on ne doit pas utiliser de cache
if ( $verifyCache === false )
{
call_user_func_array ( array ( $controller , $methodName ), $params ); //On appel la methode, en lui passant les arguments necessaires
return null ;
}
//Si on doit utiliser un cache avec un nouveau fichier
if ( $verifyCache [ 'state' ] == false )
{
//On créer le fichier avec le contenu adapté
ob_start ();
call_user_func_array ( array ( $controller , $methodName ), $params ); //On appel la methode, en lui passant les arguments necessaires
$content = ob_get_contents ();
file_put_contents ( PWD_CACHE . $verifyCache [ 'file' ], $content );
ob_end_clean ();
}
//On utilise le fichier de cache
readfile ( PWD_CACHE . $verifyCache [ 'file' ]);
}
2015-02-17 16:17:38 +01:00
}