[Tuto : créer un router] : warning preg_match() à la 32min

Par JeremyB, il y a 8 ans


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().

Ce que je fais

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); } } ?>

Ce que je veux

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.

Ce que j'obtiens

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 !

1 réponse

JeremyB, il y a 8 ans

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 ?