settings = $settings; } /** * Dispatch the request to the appropriate controller and action. */ public function dispatch(): void { // Get URL path (remove query string) $uri = $_SERVER['REQUEST_URI'] ?? '/'; if (($pos = strpos($uri, '?')) !== false) { $uri = substr($uri, 0, $pos); } // Remove base URL if needed (for subdirectory) $base = $this->settings->get('APP_URL', ''); if ($base && str_starts_with($uri, $base)) { $uri = substr($uri, strlen($base)); } // Trim slashes $uri = trim($uri, '/'); // If empty, set to default controller/action if ($uri === '') { $uri = $this->settings->get('default.route', 'home/index'); } // Split by slash $segments = explode('/', $uri); // Determine controller, action, and parameters $adminModule = false; if (!empty($segments[0]) && strtolower($segments[0]) === 'admin') { $adminModule = true; // controller segment is next $controllerSegment = !empty($segments[1]) ? $segments[1] : 'dashboard'; // action segment is next after that $actionSegment = !empty($segments[2]) ? $segments[2] : 'index'; // remove admin, controller, action from segments for params array_shift($segments); // admin array_shift($segments); // controller array_shift($segments); // action $controllerName = 'App\\Controllers\\Admin\\' . ucfirst(strtolower($controllerSegment)) . 'Controller'; $actionName = strtolower($actionSegment); } else { // standard route $controllerName = !empty($segments[0]) ? 'App\Controller\' . ucfirst(strtolower($segments[0])) . 'Controller' : 'App\Controller\' . 'HomeController';$actionName = !empty($segments[1]) ? strtolower($segments[1]) : 'index'; // remove controller and action from segments array_shift($segments); // controller if (!empty($segments)) { array_shift($segments); // action } } // Remaining segments are params in key/value pairs? We'll treat as pairs. $params = []; for ($i = 0; $i < count($segments); $i += 2) { $key = $segments[$i] ?? ''; $value = $segments[$i + 1] ?? null; if ($key !== '') { $params[$key] = $value; } } // Check if controller class exists if (!class_exists($controllerClass = $controllerName)) { // Try to load default controller (HomeController) $controllerClass = "App\\Controllers\\HomeController"; if (!class_exists($controllerClass)) { // If still not found, show 404 $this->notFound(); return; } // Adjust action if needed (maybe default) // If we were looking for admin controller and failed, maybe fallback to home? but we keep 404. } // Instantiate controller try { $controller = new $controllerClass(new \App\Core\Settings()); } catch (\Throwable $e) { // If constructor fails, show error $this->errorResponse($e); return; } // Check if action method exists if (!method_exists($controller, $actionName)) { $this->notFound(); return; } // Call beforeAction hook if exists if (method_exists($controller, 'beforeAction')) { $controller->beforeAction($actionName); } // Call the action with parameters try { // We'll pass params as arguments; but for simplicity, we'll set them as controller properties $controller->params = $params; $controller->$actionName(); } catch (\Throwable $e) { $this->errorResponse($e); return; } // Call afterAction hook if exists if (method_exists($controller, 'afterAction')) { $controller->afterAction($actionName); } } /** * Handle 404 Not Found. */ protected function notFound(): void { http_response_code(404); $this->errorResponse(new \Exception('الصفحة غير موجودة', 404)); } /** * Handle error response. * * @param \Throwable $exception */ protected function errorResponse(\Throwable $exception): void { // Use the same error handler logic but we can just forward to error handler $handler = new \App\Core\ErrorHandler(new \App\Core\Settings()); $handler->renderResponse($exception); }}