2
0
Web/Web.php

170 lines
4.9 KiB
PHP

<?php
require_once __DIR__ . '/Methods.php';
require_once __DIR__ . '/Request.php';
require_once __DIR__ . '/Response.php';
require_once __DIR__ . '/Context.php';
require_once __DIR__ . '/Router.php';
require_once __DIR__ . '/ErrorHandler.php';
/**
* Web is the application controller itself
*/
class Web
{
private Router $router;
private array $middleware = [];
private Context $context;
private ErrorHandler $errorHandler;
public function __construct(bool $debug = false)
{
$this->router = new Router();
$this->errorHandler = new ErrorHandler($debug);
}
public function use(callable $middleware): self
{
$this->middleware[] = $middleware;
return $this;
}
public function get(string $route, callable $handler): self
{
$this->router->get($route, $handler);
return $this;
}
public function post(string $route, callable $handler): self
{
$this->router->post($route, $handler);
return $this;
}
public function put(string $route, callable $handler): self
{
$this->router->put($route, $handler);
return $this;
}
public function patch(string $route, callable $handler): self
{
$this->router->patch($route, $handler);
return $this;
}
public function delete(string $route, callable $handler): self
{
$this->router->delete($route, $handler);
return $this;
}
public function head(string $route, callable $handler): self
{
$this->router->head($route, $handler);
return $this;
}
public function route(string $method, string $route, callable $handler): self
{
$this->router->add($method, $route, $handler);
return $this;
}
public function group(string $prefix, callable $callback): self
{
$originalRouter = $this->router;
$groupRouter = new Router();
$this->router = $groupRouter;
$callback($this);
foreach ($groupRouter->dump() as $path => $methods) {
$this->addGroupRoutes($originalRouter, $prefix, $path, $methods);
}
$this->router = $originalRouter;
return $this;
}
public function setErrorHandler(int $status, callable $handler): self
{
$this->errorHandler->register($status, $handler);
return $this;
}
public function setDefaultErrorHandler(callable $handler): self
{
$this->errorHandler->setDefaultHandler($handler);
return $this;
}
private function addGroupRoutes(Router $router, string $prefix, string $path, mixed $node, string $currentPath = ''): void
{
if ($path !== '') $currentPath = $currentPath ? "$currentPath/$path" : $path;
if (!is_array($node)) return;
foreach ($node as $key => $value) {
if (in_array($key, ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'])) {
$fullPath = rtrim($prefix, '/') . '/' . ltrim($currentPath, '/');
$fullPath = str_replace(':x', ':param', $fullPath);
$router->add($key, $fullPath, $value);
} elseif (is_array($value)) {
$this->addGroupRoutes($router, $prefix, $key, $value, $currentPath);
}
}
}
public function run(): void
{
$this->context = new Context();
try {
$next = function() {
$result = $this->router->lookup(
$this->context->request->method,
$this->context->request->path
);
if ($result['code'] === 404) {
$this->errorHandler->handle($this->context, 404);
return;
}
if ($result['code'] === 405) {
$this->errorHandler->handle($this->context, 405);
return;
}
$this->context->request->params = $result['params'];
$handler = $result['handler'];
$response = $handler($this->context, ...$result['params']);
if ($response instanceof Response) {
$response->send();
} elseif (is_array($response) || is_object($response)) {
$this->context->json($response);
} elseif (is_string($response)) {
$this->context->text($response);
}
};
$chain = array_reduce(
array_reverse($this->middleware),
function($next, $middleware) {
return function() use ($middleware, $next) {
$middleware($this->context, $next);
};
},
$next
);
$chain();
} catch (Exception $e) {
$this->errorHandler->handleException($this->context, $e);
}
}
}