chore: complete update
This commit is contained in:
@@ -4,8 +4,12 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Core;
|
||||
|
||||
final class RouteCompiler
|
||||
use App\Framework\Router\CompiledPattern;
|
||||
use App\Framework\Router\CompiledRoutes;
|
||||
|
||||
final readonly class RouteCompiler implements AttributeCompiler
|
||||
{
|
||||
private array $named;
|
||||
/**
|
||||
* @param array<int, array{method: string, path: string, controller: class-string, handler: string}> $routes
|
||||
* @return array<string, array{static: array<string, array>, dynamic: array<int, array{regex: string, params: array, handler: array}>}>
|
||||
@@ -13,36 +17,70 @@ final class RouteCompiler
|
||||
public function compile(array $routes): array
|
||||
{
|
||||
$compiled = [];
|
||||
$named = [];
|
||||
|
||||
foreach ($routes as $route) {
|
||||
$method = strtoupper($route['http_method']);
|
||||
|
||||
$method = is_string($route['http_method']) ? strtoupper($route['http_method']) : $route['http_method']->value;
|
||||
$path = $route['path'];
|
||||
$routeName = $route['name'] ?? '';
|
||||
|
||||
$compiled[$method] ??= ['static' => [], 'dynamic' => []];
|
||||
|
||||
if (! str_contains($path, '{')) {
|
||||
// Statische Route
|
||||
$compiled[$method]['static'][$path] = new StaticRoute(
|
||||
$staticRoute = new StaticRoute(
|
||||
$route['class'],
|
||||
$route['method'],
|
||||
$route['parameters']
|
||||
$route['parameters'] ?? [],
|
||||
$routeName,
|
||||
$path,
|
||||
$route['attributes']
|
||||
);
|
||||
|
||||
$compiled[$method]['static'][$path] = $staticRoute;
|
||||
|
||||
if($routeName) {
|
||||
$named[$routeName] = $staticRoute;
|
||||
}
|
||||
|
||||
} else {
|
||||
// Dynamische Route
|
||||
$paramNames = [];
|
||||
$regex = $this->convertPathToRegex($path, $paramNames);
|
||||
$compiled[$method]['dynamic'][] = new DynamicRoute(
|
||||
|
||||
$dynamicRoute = new DynamicRoute(
|
||||
$regex,
|
||||
$paramNames,
|
||||
$route['class'],
|
||||
$route['method'],
|
||||
$route['parameters']
|
||||
$route['parameters'],
|
||||
[],
|
||||
$routeName,
|
||||
$path,
|
||||
$route['attributes']
|
||||
);
|
||||
|
||||
$compiled[$method]['dynamic'][] = $dynamicRoute;
|
||||
|
||||
if($routeName) {
|
||||
$named[$routeName] = $dynamicRoute;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!isset($this->named)) {
|
||||
$this->named = $named;
|
||||
}
|
||||
|
||||
return $compiled;
|
||||
}
|
||||
|
||||
public function compileNamedRoutes(array $routes): array
|
||||
{
|
||||
return $this->named;
|
||||
}
|
||||
|
||||
/**
|
||||
* Konvertiert zB. /user/{id}/edit → ~^/user/([^/]+)/edit$~ und gibt ['id'] als Parameternamen zurück.
|
||||
*
|
||||
@@ -53,12 +91,77 @@ final class RouteCompiler
|
||||
private function convertPathToRegex(string $path, array &$paramNames): string
|
||||
{
|
||||
$paramNames = [];
|
||||
$regex = preg_replace_callback('#\{(\w+)\}#', function ($matches) use (&$paramNames) {
|
||||
$regex = preg_replace_callback('#\{(\w+)(\*)?}#', function ($matches) use (&$paramNames) {
|
||||
$paramNames[] = $matches[1];
|
||||
|
||||
return '([^/]+)';
|
||||
// Wenn {id*} dann erlaube Slashes, aber mache es non-greedy
|
||||
if (isset($matches[2]) && $matches[2] === '*') {
|
||||
return '(.+?)'; // Non-greedy: matcht so wenig wie möglich
|
||||
}
|
||||
|
||||
return '([^/]+)'; // Keine Slashes
|
||||
}, $path);
|
||||
|
||||
return '~^' . $regex . '$~';
|
||||
}
|
||||
|
||||
public function getAttributeClass(): string
|
||||
{
|
||||
return Route::class;
|
||||
}
|
||||
|
||||
public function compileOptimized(array $routes): CompiledRoutes
|
||||
{
|
||||
$compiled = $this->compile($routes);
|
||||
$optimizedStatic = [];
|
||||
$optimizedDynamic = [];
|
||||
|
||||
foreach($compiled as $method => $routes) {
|
||||
$optimizedStatic[$method] = $routes['static'];
|
||||
|
||||
if(!empty($routes['dynamic'])) {
|
||||
$optimizedDynamic[$method] = $this->createCompiledPattern($routes['dynamic']);
|
||||
}
|
||||
}
|
||||
|
||||
return new CompiledRoutes($optimizedStatic, $optimizedDynamic, $this->named);
|
||||
}
|
||||
|
||||
private function createCompiledPattern(mixed $dynamicRoutes): CompiledPattern
|
||||
{
|
||||
$patterns = [];
|
||||
$routeData = [];
|
||||
$currentIndex = 1; // Nach Full Match (Index 0)
|
||||
|
||||
foreach($dynamicRoutes as $index => $route) {
|
||||
$pattern = $this->stripAnchors($route->regex);
|
||||
$patterns[] = "({$pattern})";
|
||||
|
||||
// Route-Gruppe Index merken
|
||||
$routeGroupIndex = $currentIndex++;
|
||||
|
||||
// Parameter-Mapping KORREKT berechnen
|
||||
$paramMap = [];
|
||||
foreach($route->paramNames as $paramName) {
|
||||
$paramMap[$paramName] = $currentIndex++;
|
||||
}
|
||||
|
||||
$routeData[$index] = [
|
||||
'route' => $route,
|
||||
'paramMap' => $paramMap,
|
||||
'routeGroupIndex' => $routeGroupIndex
|
||||
];
|
||||
}
|
||||
|
||||
$combinedRegex = '~^(?:' . implode('|', $patterns) . ')$~';
|
||||
return new CompiledPattern($combinedRegex, $routeData);
|
||||
}
|
||||
|
||||
private function stripAnchors($regex): string
|
||||
{
|
||||
if (preg_match('/^~\^(.+)\$~$/', $regex, $matches)) {
|
||||
return $matches[1];
|
||||
}
|
||||
return $regex;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user