Refactor routing.

This commit is contained in:
Greg Sarjeant 2025-06-03 18:01:50 -04:00
parent 9b6a42de7e
commit 97e2c205a3
2 changed files with 52 additions and 58 deletions

View File

@ -1,42 +1,34 @@
<?php <?php
// TODO - I *think* what I want to do is define just this, then load up all the classes. // Define all the important paths
// Then I can define all this other boilerplate in Config or Util or whatever.
// I'll have one chicken-and-egg problem with the source directory, but that's not a big deal.
define('APP_ROOT', dirname(dirname(__FILE__))); define('APP_ROOT', dirname(dirname(__FILE__)));
// TODO - move all this to a config class?
define('SRC_DIR', APP_ROOT . '/src'); define('SRC_DIR', APP_ROOT . '/src');
define('STORAGE_DIR', APP_ROOT . '/storage'); define('STORAGE_DIR', APP_ROOT . '/storage');
define('TEMPLATES_DIR', APP_ROOT . '/templates'); define('TEMPLATES_DIR', APP_ROOT . '/templates');
define('TICKS_DIR', STORAGE_DIR . '/ticks'); define('TICKS_DIR', STORAGE_DIR . '/ticks');
define('DATA_DIR', STORAGE_DIR . '/db'); define('DATA_DIR', STORAGE_DIR . '/db');
define('DB_FILE', DATA_DIR . '/tkr.sqlite'); define('DB_FILE', DATA_DIR . '/tkr.sqlite');
// Defining this in the index instead of lib/util.php // Load all classes from the src/ directory
// to avoid chicken-and-egg issues with including it function loadClasses(): void {
function recursive_glob(string $pattern, string $directory): array {
$files = [];
$iterator = new RecursiveIteratorIterator( $iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($directory) new RecursiveDirectoryIterator(SRC_DIR)
); );
// load base classes first
require_once SRC_DIR . '/Controller/Controller.php';
// load everything else
foreach ($iterator as $file) { foreach ($iterator as $file) {
if ($file->isFile() && fnmatch($pattern, $file->getFilename())) { if ($file->isFile() && fnmatch('*.php', $file->getFilename())) {
$files[] = $file->getPathname(); require_once $file;
} }
} }
return $files;
} }
// load base classes first loadClasses();
require_once SRC_DIR . '/Controller/Controller.php';
// load everything else
foreach (recursive_glob('*.php', SRC_DIR) as $file) {
require_once $file;
}
// Everything's loaded. Now we can start ticking.
Util::confirm_setup(); Util::confirm_setup();
Session::start(); Session::start();
Session::generateCsrfToken(); Session::generateCsrfToken();
@ -47,7 +39,7 @@ $method = $_SERVER['REQUEST_METHOD'];
$request = $_SERVER['REQUEST_URI']; $request = $_SERVER['REQUEST_URI'];
$path = parse_url($request, PHP_URL_PATH); $path = parse_url($request, PHP_URL_PATH);
// return a 404 if s request for a .php file gets this far. // return a 404 if a request for a .php file gets this far.
if (preg_match('/\.php$/', $path)) { if (preg_match('/\.php$/', $path)) {
http_response_code(404); http_response_code(404);
echo '<h1>404 Not Found</h1>'; echo '<h1>404 Not Found</h1>';
@ -62,39 +54,41 @@ if (strpos($path, $config->basePath) === 0) {
$path = trim($path, '/'); $path = trim($path, '/');
function route(string $pattern, string $controller, array $methods = ['GET']) { // Main router function
global $path, $method; function route(string $requestPath, string $requestMethod, array $routeHandlers): bool {
foreach ($routeHandlers as $routeHandler) {
$routePattern = $routeHandler[0];
$controller = $routeHandler[1];
$methods = $routeHandler[2] ?? ['GET'];
if (!in_array($method, $methods)) { $routePattern = preg_replace('/\{([^}]+)\}/', '([^/]+)', $routePattern);
return false; $routePattern = '#^' . $routePattern . '$#';
}
$pattern = preg_replace('/\{([^}]+)\}/', '([^/]+)', $pattern); if (preg_match($routePattern, $requestPath, $matches)) {
$pattern = '#^' . $pattern . '$#'; if (in_array($requestMethod, $methods)){
// Save any path elements we're interested in
// (but discard the match on the entire path)
array_shift($matches);
if (preg_match($pattern, $path, $matches)) { if (strpos($controller, '@')) {
array_shift($matches); [$controllerName, $methodName] = explode('@', $controller);
} else {
// Default to 'index' method if no method specified
$controllerName = $controller;
$methodName = 'index';
}
if (strpos($controller, '@') !== false) { $instance = new $controllerName();
[$className, $methodName] = explode('@', $controller); call_user_func_array([$instance, $methodName], $matches);
} else { return true;
// Default to 'index' method if no method specified }
$className = $controller;
$methodName = 'index';
} }
$instance = new $className();
call_user_func_array([$instance, $methodName], $matches);
return true;
} }
return false; return false;
} }
// Set content type $routeHandlers = [
header('Content-Type: text/html; charset=utf-8');
// routes
$routes = [
['', 'HomeController'], ['', 'HomeController'],
['', 'HomeController@handleTick', ['POST']], ['', 'HomeController@handleTick', ['POST']],
['admin', 'AdminController'], ['admin', 'AdminController'],
@ -108,12 +102,12 @@ $routes = [
['feed/atom', 'FeedController@atom'], ['feed/atom', 'FeedController@atom'],
]; ];
foreach ($routes as $routeConfig) { // Set content type
$pattern = $routeConfig[0]; header('Content-Type: text/html; charset=utf-8');
$controller = $routeConfig[1];
$methods = $routeConfig[2] ?? ['GET'];
if (route($pattern, $controller, $methods)) { // Render the requested route or throw a 404
break; if (!route($path, $method, $routeHandlers)){
} http_response_code(404);
}; echo "404 - Page Not Found";
exit;
}

View File

@ -17,7 +17,7 @@ class AdminController extends Controller {
// POST handler // POST handler
// save updated settings // save updated settings
public function save(){ public function handleSave(){
$isLoggedIn = isset($_SESSION['user_id']); $isLoggedIn = isset($_SESSION['user_id']);
if (!$isLoggedIn){ if (!$isLoggedIn){
header('Location: ' . $config->basePath . 'login.php'); header('Location: ' . $config->basePath . 'login.php');