Bonjour,
Je suis le tutoriel pour créer un router. Avant la 32ème minute, tout fonctionne, j'obtiens la même chose que Grafikart lors des var_dump() et autres. Par contre, une fois qu'on a mis en place la méthode privée paramMatch(), je n'obtiens plus le même résultat et ai un joli warning sur un preg_match().
La page routes.php sert à écrire mes routes :
<?php
$router = new \Core\Router\Router($_GET['url']);
$router->get('/posts/:id-:slug', function($id, $slug){
echo "Article : $slug et $id";
})->with('id', '[O-9]+')->with('slug', '[a-z\-0-9]+');
$router->run();
?>
La classe Router.php :
<?php
namespace Core\Router;
/*
|--------------------------------------------------------------------------
| Router
|--------------------------------------------------------------------------
|
| Créer les routes pour le site
|
*/
class Router {
/**
* Le point d'entrée du router, l'URL : $_GET['url']
* @var string
*/
private $url;
/**
* On stock les routes dans un tableau
* @var array
*/
private $routes = [];
/**
* Les routes sont nommées pour les retrouver plus facilement
* @var array
*/
private $namedRoutes = [];
// private $GroupPattern = '';
public function __construct($url){
$this->url = $url;
}
/**
* Créer une route avec la method GET
* @param string $path route a inclure dans le tableau des routes
* @param string $callable controller a appeller
* @return object retourne l'objet en cours
*/
public function get($path, $callable){
$route = new Route($path, $callable);
$this->routes["GET"][] = $route;
return $route; // On retourne l'instance de la classe route pour "enchainer" les méthodes
}
public function post($path, $callable){
$route = new Route($path, $callable);
$this->routes["POST"][] = $route;
return $route;
}
/**
* Vérifie si une URL correspond à une "route"
* @param string $param nom du parametre a verifier
* @param string $regex regex a vérifier
* @return object retiourne l'objet en cours
*/
public function run(){
if(!isset($this->routes[$_SERVER['REQUEST_METHOD']])){
throw new RouterException('REQUEST_METHOD does not exist');
}
foreach($this->routes[$_SERVER['REQUEST_METHOD']] as $route){
if($route->match($this->url)){
return $route->call();
}
}
throw new RouterException('No matching routes');
}
}
?>
La classe Route.php :
<?php
namespace Core\Router;
/*
|--------------------------------------------------------------------------
| Route
|--------------------------------------------------------------------------
|
| Décortique l'url pour avoir :
| - le controlleur
| - la méthode
| - les paramètres (id, slug etc)
|
*/
class Route {
/**
* La route à décortiquer
* @var string
*/
private $path;
/**
* L'appel au controlleur et la méthode
* @var string
*/
private $callable;
/**
* Les correspondances entre la route et l'URL
* @var array
*/
private $matches = [];
/**
* Les paramètres trouvés : id, slug, etc
* @var array
*/
private $params = [];
public function __construct($path, $callable){
$this->path = trim($path, '/');
$this->callable = $callable;
}
/**
* Trouve la correspondance entre les routes et l'URL
* @param string $url URL à comparer
* @param string $route Route avec laquelle le comparer
* @return bool Retourne un bouléen si la correspondance est trouvée
*/
public function match($url){
$url = trim($url, '/');
$path = preg_replace_callback('#:([\w]+)#', [$this, 'paramMatch'], $this->path);
$regex = "#^$path$#i";
if(!preg_match($regex, $url, $matches)){
return false;
}
array_shift($matches);
// On sauvegarde les paramètres dans l'instance pour la méthode call()
$this->matches = $matches;
return true;
}
/**
* Récupère et stocke les paramètres
* @param string $match Correspondance
* @return string Retourne le pattern
*/
private function paramMatch($match)
{
if (isset($this->params[$match[1]])) {
return '(' . $this->params[$match[1]] . ')';
}
return '([^/]+)';
}
/**
* Vérifie la validité des paramètres
* @param string $param Nom du parametre à vérifier
* @param string $regex Regex à vérifier
* @return object Retourne l'objet en cours
*/
public function with($param, $regex){
// $this->params[$param] = str_replace('(', '(?:', $regex);
$this->params[$param] = $regex;
// Permet de faire du fluence pour enchainer les arguments
// $router->get('/blog/:id', Blog#article)->with('id', '[O-9]+');
return $this;
}
/**
* Appel le controlleur et la méthode
* @param string callable Controlleur et méthode à appeler
* @return string matches Paramètres à envoyer
*/
public function call(){
return call_user_func_array($this->callable, $this->matches);
}
}
?>
Je veux obtenir comme Grafikart à la 32ème minute et 10s pour être précis. C'est-à-dire le tableau récupérant les paramètres id et slug correctement.
Lorsque je place un var_dump($this->matches) dans la méthode call() de Route.php pour savoir si il a bien matcher les paramètres, je récupère un warning disant :
Warning: preg_match(): Compilation failed: range out of order in character class at offset 11 in /test/core/Router/Route.php on line 57
Soit le preg_match() dans la méthode match() de Route.php. J'ai beau chercher, même sur google, je ne trouve pas.
Et ci-dessous ne résout non plus le problème..
if(preg_match($regex, $url, $matches) === false){
return false;
}
Merci d'avance !
J'ai résolu mon problème mais je ne comprend pas pourquoi.. C'était un problème de regex, sur l'id. Sur la page routes.php où je crée les routes, il y avait un soucis avec : with('id', '[0-9]+').
[0-9] ne fonctionne pas, seul [\d] fonctionne, ce qui donne : with('id', '[\d]+').
Une explication ?