configureRoutes(); } /** * Configure toutes les routes de l'application */ private function configureRoutes(): void { // Routes publiques $this->post('login', ['LoginController', 'login']); $this->post('register', ['LoginController', 'register']); $this->post('lostpassword', ['LoginController', 'lostPassword']); // Route pour les logs $this->post('log', ['LogController', 'index']); // Routes privées utilisateurs $this->get('users', ['UserController', 'getUsers']); $this->get('users/:id', ['UserController', 'getUserById']); $this->post('users', ['UserController', 'createUser']); $this->put('users/:id', ['UserController', 'updateUser']); $this->delete('users/:id', ['UserController', 'deleteUser']); $this->post('logout', ['LoginController', 'logout']); // Routes entités $this->get('entites', ['EntiteController', 'getEntites']); $this->get('entites/:id', ['EntiteController', 'getEntiteById']); $this->get('entites/postal/:code', ['EntiteController', 'getEntiteByPostalCode']); $this->put('entites/:id', ['EntiteController', 'updateEntite']); // Routes opérations $this->get('operations', ['OperationController', 'getOperations']); $this->get('operations/:id', ['OperationController', 'getOperationById']); $this->post('operations', ['OperationController', 'createOperation']); $this->put('operations/:id', ['OperationController', 'updateOperation']); $this->delete('operations/:id', ['OperationController', 'deleteOperation']); // Routes d'export d'opérations $this->get('operations/:id/export/excel', ['OperationController', 'exportExcel']); $this->get('operations/:id/export/json', ['OperationController', 'exportJson']); $this->get('operations/:id/export/full', ['OperationController', 'exportFull']); $this->get('operations/:id/backups', ['OperationController', 'getBackups']); $this->get('operations/:id/backups/:backup_id', ['OperationController', 'downloadBackup']); $this->delete('operations/:id/backups/:backup_id', ['OperationController', 'deleteBackup']); // Routes passages $this->get('passages', ['PassageController', 'getPassages']); $this->get('passages/:id', ['PassageController', 'getPassageById']); $this->get('passages/operation/:operation_id', ['PassageController', 'getPassagesByOperation']); $this->post('passages', ['PassageController', 'createPassage']); $this->put('passages/:id', ['PassageController', 'updatePassage']); $this->delete('passages/:id', ['PassageController', 'deletePassage']); // Routes villes $this->get('villes', ['VilleController', 'searchVillesByPostalCode']); // Routes fichiers $this->get('files/browse', ['FileController', 'browse']); $this->get('files/search', ['FileController', 'search']); $this->get('files/stats', ['FileController', 'getStats']); $this->get('files/metadata', ['FileController', 'getMetadata']); $this->get('files/list/:support/:id', ['FileController', 'listBySupport']); $this->get('files/info/:id', ['FileController', 'getFileInfo']); $this->get('files/download/:id', ['FileController', 'download']); $this->delete('files/:id', ['FileController', 'deleteFile']); } public function handle(): void { $method = $_SERVER['REQUEST_METHOD']; $uri = $this->normalizeUri($_SERVER['REQUEST_URI']); error_log("Initial URI: $uri"); // Handle CORS preflight if ($method === 'OPTIONS') { header('HTTP/1.1 200 OK'); exit(); } // Prendre le préfixe API à partir de la constante $apiPrefix = self::API_PREFIX; // Vérifier si l'URI commence bien par le préfixe API $prefixMatch = strpos($uri, $apiPrefix) === 0; if (!$prefixMatch) { Response::json([ 'error' => 'Invalid API prefix', 'path' => $uri, 'expected_prefix' => $apiPrefix ], 404); return; } // Extraire l'endpoint en retirant le préfixe API $endpoint = substr($uri, strlen($apiPrefix) + 1); // +1 pour le slash $endpoint = trim($endpoint, '/'); // Check if endpoint is public if ($this->isPublicEndpoint($endpoint)) { error_log("Public endpoint found: $endpoint"); $route = $this->findRoute($method, $endpoint); if ($route) { $this->executeRoute($route); return; } } else { error_log("Private endpoint: $endpoint"); // Private route - check auth first Session::requireAuth(); $route = $this->findRoute($method, $endpoint); if ($route) { $this->executeRoute($route); return; } } // No route found Response::json([ 'error' => 'Route not found', 'endpoint' => $endpoint, 'uri' => $uri ], 404); } private function normalizeUri(string $uri): string { return trim(preg_replace('#/+#', '/', parse_url($uri, PHP_URL_PATH)), '/'); } private function isPublicEndpoint(string $endpoint): bool { return in_array($endpoint, $this->publicEndpoints); } private function executeRoute(array $route): void { [$controllerName, $method] = $route['handler']; // Essayer de trouver le contrôleur en tenant compte des namespaces possibles $classNames = [ $controllerName, // Sans namespace "\\App\\Controllers\\$controllerName", // Avec namespace complet "\\$controllerName" // Avec namespace racine ]; $controllerClass = null; foreach ($classNames as $className) { if (class_exists($className)) { $controllerClass = $className; break; } } if ($controllerClass === null) { // Classe non trouvée, gérer l'erreur Response::json([ 'error' => 'Controller not found', 'controller' => $controllerName, 'status' => 'error', 'message' => 'Controller not found', 'tried_namespaces' => implode(', ', $classNames) ], 404); return; } $controller = new $controllerClass(); if (!empty($route['params'])) { $controller->$method(...$route['params']); } else { $controller->$method(); } } public function get(string $path, array $handler): void { $this->addRoute('GET', $path, $handler); } public function post(string $path, array $handler): void { $this->addRoute('POST', $path, $handler); } public function put(string $path, array $handler): void { $this->addRoute('PUT', $path, $handler); } public function delete(string $path, array $handler): void { $this->addRoute('DELETE', $path, $handler); } private function addRoute(string $method, string $path, array $handler): void { // Normalize the path $path = trim($path, '/'); $this->routes[$method][$path] = $handler; } private function findRoute(string $method, string $uri): ?array { if (!isset($this->routes[$method])) { error_log("Méthode $method non trouvée dans les routes"); return null; } $uri = trim($uri, '/'); error_log("Recherche de route pour: méthode=$method, uri=$uri"); error_log("Routes disponibles pour $method: " . implode(', ', array_keys($this->routes[$method]))); foreach ($this->routes[$method] as $route => $handler) { // Correction: utiliser :param au lieu de {param} $pattern = preg_replace('/:([^\/]+)/', '([^/]+)', $route); $pattern = "@^" . $pattern . "$@D"; error_log("Test pattern: $pattern contre uri: $uri"); if (preg_match($pattern, $uri, $matches)) { error_log("Route trouvée! Pattern: $pattern, Handler: {$handler[0]}::{$handler[1]}"); array_shift($matches); return [ 'handler' => $handler, 'params' => $matches ]; } } error_log("Aucune route trouvée pour $method $uri"); return null; } }