WizdomWeb/app/Core/Router.php

130 lines
4.4 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/**
* ============================================
* File: Router.php
* Path: /app/Core/
* Purpose: Core router handling HTTP methodspecific route dispatching with dynamic path and closure support.
* Version: 1.3
* Author: Wizdom Networks
* ============================================
*/
namespace WizdomNetworks\WizeWeb\Core;
use WizdomNetworks\WizeWeb\Utilities\Logger;
use WizdomNetworks\WizeWeb\Utilities\ErrorHandler;
class Router
{
private array $routes = [];
/**
* Registers a new route.
*
* @param string $path The URL path (e.g. /contact or /verify/{code}).
* @param string $controller The fully qualified controller class.
* @param string $method The method name in the controller.
* @param string $httpMethod HTTP method (GET, POST, etc.), defaults to GET.
*/
public function add(string $path, string $controller, string $method, string $httpMethod = 'GET'): void
{
$normalizedPath = trim($path, '/');
$routeKey = strtoupper($httpMethod) . ':' . $normalizedPath;
// Convert path with {param} to regex and store original keys
$paramKeys = [];
$regexPath = preg_replace_callback('/\{([a-zA-Z_][a-zA-Z0-9_]*)\}/', function ($matches) use (&$paramKeys) {
$paramKeys[] = $matches[1];
return '([^\/]+)';
}, $normalizedPath);
$this->routes[$routeKey] = [
'controller' => $controller,
'method' => $method,
'pattern' => "#^" . $regexPath . "$#",
'params' => $paramKeys
];
Logger::debug("Registering route: [$httpMethod] $path -> $controller::$method");
}
/**
* Registers a closure-based route.
*
* @param string $path
* @param \Closure $callback
* @param string $httpMethod
*/
public function addClosure(string $path, \Closure $callback, string $httpMethod = 'GET'): void
{
$routeKey = strtoupper($httpMethod) . ':' . trim($path, '/');
Logger::debug("Registering closure route: [$httpMethod] $path");
$this->routes[$routeKey] = $callback;
}
/**
* Dispatch the request based on the path and HTTP method.
*
* @param string $path The requested path (from index.php).
*/
public function dispatch($path)
{
$httpMethod = strtoupper($_SERVER['REQUEST_METHOD'] ?? 'GET');
$cleanPath = trim($path, '/');
$routeKeyBase = $httpMethod . ':';
foreach ($this->routes as $key => $route) {
if (strpos($key, $routeKeyBase) !== 0) {
continue;
}
$routePattern = $route['pattern'] ?? null;
// Handle Closure
if ($route instanceof \Closure && $key === $routeKeyBase . $cleanPath) {
Logger::info("Executing closure route: [$httpMethod] $cleanPath");
$route();
return;
}
// Handle dynamic path matches
if ($routePattern && preg_match($routePattern, $cleanPath, $matches)) {
array_shift($matches); // first match is the whole path
$params = array_combine($route['params'], $matches) ?: [];
$controllerName = $route['controller'];
$method = $route['method'];
try {
if (!class_exists($controllerName)) {
throw new \Exception("Controller not found: $controllerName");
}
$controller = new $controllerName();
if (!method_exists($controller, $method)) {
throw new \Exception("Method $method not found in $controllerName");
}
Logger::info("Executing controller: $controllerName::$method with params: " . json_encode($params));
call_user_func_array([$controller, $method], $params);
return;
} catch (\Throwable $e) {
echo "<pre>";
echo "Exception: " . $e->getMessage() . "\n";
echo "File: " . $e->getFile() . "\n";
echo "Line: " . $e->getLine() . "\n";
echo "Trace:\n" . $e->getTraceAsString();
echo "</pre>";
exit;
}
}
}
Logger::error("Route not found: [$httpMethod] $path");
http_response_code(404);
echo "404 Not Found";
}
}