Files
Woles-Framework/app/Core/Bootstrap.php

211 lines
7.2 KiB
PHP
Raw Permalink Normal View History

<?php
namespace App\Core;
use App\Core\Router;
use App\Core\Container;
use App\Core\Middleware;
use App\Core\Security;
/**
* NovaCore Framework Bootstrap
* Main application kernel
*/
class Bootstrap
{
private Container $container;
private Router $router;
private Middleware $middleware;
private Security $security;
public function __construct()
{
$this->container = new Container();
$this->router = new Router();
$this->middleware = new Middleware();
$this->security = new Security();
// Set the global container so helpers can use it
app_set_container($this->container);
$this->registerServices();
$this->loadRoutes();
$this->setupMiddleware();
}
/**
* Run the application
*/
public function run(): void
{
// Start session
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
// Initialize security
$this->security->initialize();
// Get request method and URI
$method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
$uri = parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH);
// Run middleware pipeline
$this->middleware->run($method, $uri);
// Route the request
$route = $this->router->match($method, $uri);
if (!$route) {
$this->handleNotFound();
return;
}
// Execute controller
$this->executeController($route);
}
/**
* Register services in container
*/
private function registerServices(): void
{
$this->container->singleton('request', function () {
return new Request();
});
$this->container->singleton('response', function () {
return new Response();
});
$this->container->singleton('view', function () {
return new View();
});
$this->container->singleton('security', function () {
return $this->security;
});
}
/**
* Load routes from all modules
*/
private function loadRoutes(): void
{
$modulesPath = __DIR__ . '/../Modules';
if (is_dir($modulesPath)) {
$modules = scandir($modulesPath);
foreach ($modules as $module) {
if ($module === '.' || $module === '..') continue;
$routesFile = $modulesPath . '/' . $module . '/routes.php';
if (file_exists($routesFile)) {
// Pass router instance to routes file
$router = $this->router;
require $routesFile;
}
}
}
}
/**
* Setup default middleware stack
*/
private function setupMiddleware(): void
{
$this->middleware->add(new \App\Core\Middleware\SecurityMiddleware());
$this->middleware->add(new \App\Core\Middleware\CsrfMiddleware());
}
/**
* Execute controller method
*/
private function executeController(array $route): void
{
[$controllerClass, $method] = explode('@', $route['handler']);
// Normalize controller class to fully-qualified name
if (!str_contains($controllerClass, '\\')) {
// No backslash provided → assume default Controller in module
$controllerClass = "App\\Modules\\{$route['module']}\\Controller";
} else {
// Has backslash but may be relative like "Home\\Controller"
if (strpos($controllerClass, 'App\\') !== 0) {
$segments = explode('\\', $controllerClass);
$moduleName = $segments[0] ?? $route['module'];
$className = end($segments);
$controllerClass = "App\\Modules\\{$moduleName}\\{$className}";
}
}
if (!class_exists($controllerClass)) {
$this->handleNotFound();
return;
}
$controller = new $controllerClass();
if (!method_exists($controller, $method)) {
$this->handleNotFound();
return;
}
// Inject dependencies
$this->container->inject($controller);
// Execute method
$result = $controller->$method();
// Handle response
if ($result instanceof Response) {
$result->send();
} elseif (is_array($result) || is_object($result)) {
$response = $this->container->get('response');
$response->json($result)->send();
} else {
echo $result;
}
}
/**
* Handle 404 Not Found
*/
private function handleNotFound(): void
{
try {
$errorController = new \App\Modules\Error\Controller();
$errorController->notFound();
} catch (\Throwable $e) {
// Fallback to basic 404
http_response_code(404);
echo "<!DOCTYPE html>\n";
echo "<html>\n<head>\n";
echo "<title>404 - Page Not Found</title>\n";
echo "<script src=\"https://cdn.tailwindcss.com\"></script>\n";
echo "<link href=\"https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap\" rel=\"stylesheet\">\n";
echo "</head>\n<body class=\"font-sans bg-slate-50 min-h-screen\">\n";
echo "<div class=\"min-h-screen flex items-center justify-center px-4 sm:px-6 lg:px-8\">\n";
echo "<div class=\"max-w-md w-full space-y-8\">\n";
echo "<div class=\"text-center\">\n";
echo "<div class=\"mx-auto h-24 w-24 bg-slate-100 rounded-full flex items-center justify-center mb-6\">\n";
echo "<svg class=\"h-12 w-12 text-slate-400\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n";
echo "<path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M9.172 16.172a4 4 0 015.656 0M9 12h6m-6-4h6m2 5.291A7.962 7.962 0 0112 15c-2.34 0-4.29-1.009-5.824-2.709M15 12a3 3 0 11-6 0 3 3 0 016 0z\"></path>\n";
echo "</svg>\n";
echo "</div>\n";
echo "<h1 class=\"text-6xl font-bold text-slate-900 mb-2\">404</h1>\n";
echo "<h2 class=\"text-2xl font-semibold text-slate-900 mb-4\">Page Not Found</h2>\n";
echo "<p class=\"text-slate-600 mb-8\">The page you are looking for could not be found.</p>\n";
echo "<div class=\"space-y-4\">\n";
echo "<a href=\"/\" class=\"w-full flex justify-center py-3 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-slate-900 hover:bg-slate-800 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-slate-900\">Return to Home</a>\n";
echo "<button onclick=\"history.back()\" class=\"w-full flex justify-center py-3 px-4 border border-slate-300 rounded-md shadow-sm text-sm font-medium text-slate-700 bg-white hover:bg-slate-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-slate-500\">Go Back</button>\n";
echo "</div>\n";
echo "<div class=\"mt-8 text-sm text-slate-500\">If you believe this is an error, please contact support.</div>\n";
echo "</div>\n";
echo "</div>\n";
echo "</div>\n";
echo "</body>\n</html>\n";
}
}
}