Dossier spécifique Tuto Route PHP

Par SamghamiTM, il y a 10 ans


Bonjour,

Ce que je veux

Ce que je veux est assez simple à comprendre, c'est a dire que j'ai suivi ce tutoriel: https://www.grafikart.fr/tutoriels/php/router-628
Et maintenant je souhaite que chaque controller se trouve à la racine du repertoire (en au même niveau que le dossier App et non dedans)
C'est à dire que mon arborescence devrai juste être:
-App (Gestion des routes et Controller principal)
-Articles (avec a l'interieur les dossiers suivant: Controller, Vue, Model)
-Posts (avec a l'interieur les dossiers suivant: Controller, Vue, Model)

Ce que j'ai comme code

A la racine j'ai:
index.php

<?php // Inclusion de l'autoloader require "App/Autoloader.php"; // \App\Autoloader::register(); $router = new App\Router\Router($_GET['url']); $router->get('/', function(){ echo 'Homepage';}); $router->get('/posts', function(){ echo 'Tous les articles';}); $router->get('/posts/:slug-:id/:page', "Posts#show")->with('id', '[0-9]+')->with('page','[0-9]+')->with('slug', '[a-z\0-9]+'); $router->get('/posts/:slug-:id/', "Posts#show")->with('id', '[0-9]+')->with('slug', '[a-z\0-9]+'); $router->get('/articles/:id-:slug', "Articles#show")->with('id', '[0-9]+')->with('slug', '[a-z\0-9]+'); $router->get('/article/:id-:slug', function($id, $slug) use ($router) {echo $router->url("Posts#show", ['id' => 1, 'slug' => 'salut-les-gens']);}, "posts.show")->with('id', '[0-9]+')->with('slug', '[a-z\0-9]+'); //$router->get('/posts/:slug-:id', function($slug, $id) use ($router) {echo $router->url("posts.show", ['id' => 1, 'slug' => 'salut-les-gens']);}, "posts.show")->with('id', '[0-9]+')->with('slug', '[a-z\0-9]+'); $router->post('/posts/:id', function($id){ echo 'Poster pour l\'article '.$id. "<pre>" . print_r($_POST) . '</pre>';}); $router->run();

Puis un dossier Posts, avec à l'interieur un dossier Controller qui contiens:
PostsController.php

<?php namespace Posts\Controller; class PostsController { public function show($slug,$id,$page = 1){ echo "Je suis l'article N:$id ayant pour titre $slug et je suis a la page $page"; } }

Puis dans mon dossier App, j'ai un fichier autoloader:

<?php namespace App; class Autoloader { static function register(){ spl_autoload_register(array(__CLASS__, 'autoload')); } static function autoload($class){ if(strpos($class, __NAMESPACE__ . "\\") === 0){ $class = str_replace(__NAMESPACE__ . "\\", '', $class); $class = str_replace("\\", "/", $class); require $class . ".php"; } } }

Et toujours dans le dossier App, J'ai un dossier Router qui contient:
Router.php

<?php namespace App\Router; class Router{ private $url; private $routes = []; private $nameRoutes = []; public function __construct($url) { $this->url = $url; } public function get($path, $callable, $name = null) { return $this->add($path,$callable,$name, 'GET'); } public function post($path, $callable, $name = null) { return $this->add($path,$callable,$name, 'GET'); } private function add($path, $callable, $name, $method){ $route = new Route($path, $callable); $this->routes[$method][] = $route; if(is_string($callable) && $name === null){ $name = $callable; } if($name){ $this->nameRoutes[$name] = $route; } return $route; } 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'); } public function url($name, $params = []){ if(!isset($this->nameRoutes[$name])){ throw new RouterException('No route matches this name'); } return $this->nameRoutes[$name]->getUrl($params); } }

Et Route.php

<?php namespace App\Router; class Route{ private $path; private $callable; private $matches = []; private $params = []; public function __construct($path, $callable) { $this->path = trim($path, '/'); $this->callable = $callable; } public function with($param, $regex){ $this->params[$param] = str_replace('(', '(?:', $regex); return $this; } 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); $this->matches = $matches; return true; } private function paramMatch($match){ if(isset($this->params[$match[1]])) { return '('. $this->params[$match[1]] . ')'; } return '([^/]+)'; } public function call(){ if(is_string($this->callable)){ $params = explode('#', $this->callable); //die(print_r($params)); $controller = "App\\Controller\\".$params[0]."Controller"; $controller = new $controller(); return call_user_func_array([$controller, $params[1]], $this->matches); }else{ return call_user_func_array($this->callable, $this->matches); } } public function getUrl($params){ $path = $this->path; foreach ($params as $k => $v) { $path = str_replace(":$k", $v, $path); } return $path; } }

Auriez-vous le moyens d'obtenir ce dont je souhaite ?

3 réponses

PhiSyX, il y a 10 ans

Yop.

Oui, il faut améliorer/modifier ton autoloader pour faire en sorte de require les autres classes dont le namespace n'est pas __NAMESPACE__. ^-^
Et modifier la variable $controller de ta méthode call (fichier Route.php) pour y mettre le bon nom de classe (+ namespace) ;)

SamghamiTM, il y a 10 ans

je débute vraiment en POO alors je ne comprend pas du tout comment faire cela :-/

PhiSyX, il y a 10 ans
  • Dans ton fichier Autoloader.php, méthode statique autoload, enlève la condition if(strpos($class, __NAMESPACE__ . "\\") === 0) et $class = str_replace(__NAMESPACE__ . "\\", '', $class);.
  • Dans ton fichier Route.php, méthode call, remplace $controller = "App\\Controller\\" . $params[0] . "Controller"; par $controller = $params[0] . "\\Controller\\" . $params[0] . "Controller";. Ceci retournera Posts\Controller\PostsController (au lieu de App\Controller\PostsController)