<?php /* * Copyright (c) 2022. Micha Espey <tracer@24unix.net> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. * */ namespace App\Service; use App\Entity\Route; use Closure; /* * A small router implementation for the address book demo. * Currently it doesn't handle GET requests, as not needed. * But if I reuse the code in my bind Api I'll enable GET as well. */ class Router { private array $routes; /* * This method takes a route like /admin/users/{user} and creates a regex to match on call * More complex routes as /posts/{thread}/show/{page} are supported as well. */ function addRoute(string $name, string $route, Closure $callback): void { // check for parameters preg_match_all(pattern: "/(?<={).+?(?=})/", subject: $route, matches: $matches); $parameters = $matches[0]; // create regex for route: $regex = preg_replace(pattern: '/(?<={).+?(?=})/', replacement: '(.*?)', subject: $route); // code below is ugly, better match including the braces $regex = str_replace(search: '{', replace: '', subject: $regex); $regex = str_replace(search: '}', replace: '', subject: $regex); $regex = '/^' . str_replace(search: "/", replace: '\\/', subject: $regex) . '$/i'; $route = new Route(name: $name, route: $route, regEx: $regex, parameters: $parameters, callback: $callback); $this->routes[] = $route; } /* * Check if there is a known route and executes the callback. * Currently no 404 handling. */ public function handleRouting(): void { $requestUri = $_SERVER['REQUEST_URI']; foreach ($this->routes as $route) { if (preg_match(pattern: $route->getRegex(), subject: $requestUri, matches: $matches)) { $parameters = []; foreach ($route->getParameters() as $id => $parameter) { $parameters[$parameter] = $matches[$id +1]; } // PHP is mad about named parameters in call_user_func // Uncaught Error: Unknown named parameter $args in … // But PHPStorm seems happy without them. So what? call_user_func($route->getCallback(), $parameters); return; } } // Throw a 404 result later … die("Invalid route: $requestUri"); } }