153 lines
No EOL
4.2 KiB
PHP
153 lines
No EOL
4.2 KiB
PHP
<?php
|
|
|
|
namespace Core\Routing;
|
|
|
|
use Core\Exceptions\ExceptionHandler;
|
|
use Core\Exceptions\Exceptions\NotFoundHttpException;
|
|
use Core\Http\Request;
|
|
use Core\Http\View\Engine;
|
|
use Exception;
|
|
|
|
class RouteDispatcher
|
|
{
|
|
/**
|
|
* Current request instance
|
|
*
|
|
* @var \Core\Http\Request
|
|
*/
|
|
private Request $request;
|
|
|
|
/**
|
|
* Collection of all routes
|
|
*
|
|
* @var array
|
|
*/
|
|
private array $routeCollection;
|
|
|
|
/**
|
|
* Dispatch the router dispatcher
|
|
*
|
|
* @param \Core\Http\Request $request
|
|
* @param array $routeCollection
|
|
* @return void
|
|
*/
|
|
public function dispatch(Request $request, array $routeCollection): void
|
|
{
|
|
$this->request = $request;
|
|
$this->routeCollection = $routeCollection;
|
|
|
|
try {
|
|
$route = $this->findMatchingRoute();
|
|
$controller = $this->instantiateController($route['controller']);
|
|
$action = $this->validateActionExists($controller, $route['action']);
|
|
$params = $this->resolveParameters($controller, $action, $route['params'] ?? []);
|
|
|
|
$this->executeAction($controller, $action, $params);
|
|
} catch (NotFoundHttpException $e) {
|
|
$this->handleException($e, 404, 'page not found');
|
|
} catch (Exception $e) {
|
|
$this->handleException($e, 500, 'something went wrong');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Locate a matching route for the incoming request.
|
|
*
|
|
* @return array
|
|
* @throws \Core\Exceptions\Exceptions\NotFoundHttpException
|
|
*/
|
|
private function findMatchingRoute(): array
|
|
{
|
|
$url = $this->request->url();
|
|
$method = $this->request->method();
|
|
|
|
$route = RouteCollection::find($method, $url);
|
|
if ($route) {
|
|
return $route;
|
|
}
|
|
|
|
throw new NotFoundHttpException(sprintf("No route found for: %s", $url));
|
|
}
|
|
|
|
/**
|
|
* Create an instance of the requested controller.
|
|
*
|
|
* @param string $controllerName
|
|
* @return object
|
|
* @throws \Core\Exceptions\Exceptions\NotFoundHttpException
|
|
*/
|
|
private function instantiateController(string $controllerName): object
|
|
{
|
|
if (!class_exists($controllerName)) {
|
|
throw new NotFoundHttpException(sprintf("Controller '%s' missing", $controllerName));
|
|
}
|
|
|
|
return new $controllerName($this->request);
|
|
}
|
|
|
|
/**
|
|
* Validate that the action exists in the controller.
|
|
*
|
|
* @param object $controller
|
|
* @param string $actionName
|
|
* @return string
|
|
* @throws \Core\Exceptions\Exceptions\NotFoundHttpException
|
|
*/
|
|
private function validateActionExists(object $controller, string $actionName): string
|
|
{
|
|
if (!method_exists($controller, $actionName)) {
|
|
throw new NotFoundHttpException(sprintf("Method '%s' not found on '%s'", $actionName, get_class($controller)));
|
|
}
|
|
|
|
return $actionName;
|
|
}
|
|
|
|
/**
|
|
* Validate and resolve parameters for the controller action.
|
|
*
|
|
* @param object $controller
|
|
* @param string $action
|
|
* @param array $params
|
|
* @return array
|
|
* @throws \Exception
|
|
*/
|
|
private function resolveParameters(object $controller, string $action, array $params): array
|
|
{
|
|
return RouteValidator::resolve($controller, $action, $params);
|
|
}
|
|
|
|
/**
|
|
* Execute the resolved action on the controller with validated parameters.
|
|
*
|
|
* @param object $controller
|
|
* @param string $action
|
|
* @param array $params
|
|
* @return void
|
|
*/
|
|
private function executeAction(object $controller, string $action, array $params): void
|
|
{
|
|
$response = $controller->$action(...$params);
|
|
|
|
if ($response instanceof Render) {
|
|
$response->render();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handle exceptions gracefully.
|
|
*
|
|
* @param Exception $e
|
|
* @param int $statusCode
|
|
* @param string $message
|
|
* @return void
|
|
*/
|
|
private function handleException(Exception $e, int $statusCode, string $message): void
|
|
{
|
|
if (env('debug')) {
|
|
ExceptionHandler::catchOne($e);
|
|
}
|
|
|
|
http_response_code($statusCode);
|
|
echo $message;
|
|
}
|
|
} |