Routing API

HTTP routing, route matching, middleware, and URL generation. These classes provide comprehensive routing functionality including parameter binding, middleware chains, and named routes for your Forge Engine applications.

Router

The main router class that manages route registration, matching, and dispatching. The Router provides a fluent interface for defining routes with various HTTP methods, middleware, and parameter constraints.

Basic Route Registration

get(string $uri, mixed $action): Route

Register a GET route.

$router = new Router();

// Simple closure route
$router->get('/', function() {
    return 'Welcome to Forge Engine!';
});

// Controller route
$router->get('/users', [UserController::class, 'index']);

// Named route
$router->get('/users', [UserController::class, 'index'])->name('users.index');

post(string $uri, mixed $action): Route

Register a POST route.

$router->post('/users', [UserController::class, 'store']);
$router->post('/login', [AuthController::class, 'login'])->name('auth.login');

put(string $uri, mixed $action): Route

Register a PUT route.

$router->put('/users/{id}', [UserController::class, 'update']);
$router->put('/posts/{id}', [PostController::class, 'update'])->name('posts.update');

delete(string $uri, mixed $action): Route

Register a DELETE route.

$router->delete('/users/{id}', [UserController::class, 'destroy']);
$router->delete('/posts/{id}', [PostController::class, 'destroy'])->name('posts.destroy');

Route Parameters

Basic Parameters

Define routes with parameters.

// Required parameter
$router->get('/users/{id}', function($id) {
    return "User ID: {$id}";
});

// Optional parameter
$router->get('/posts/{id?}', function($id = null) {
    return $id ? "Post ID: {$id}" : "All posts";
});

// Multiple parameters
$router->get('/users/{user}/posts/{post}', function($user, $post) {
    return "User: {$user}, Post: {$post}";
});

Parameter Constraints

Add constraints to route parameters.

// Numeric constraint
$router->get('/users/{id}', function($id) {
    return "User ID: {$id}";
})->where('id', '[0-9]+');

// Alpha constraint
$router->get('/posts/{slug}', function($slug) {
    return "Post slug: {$slug}";
})->where('slug', '[a-z-]+');

// Multiple constraints
$router->get('/users/{id}/posts/{slug}', function($id, $slug) {
    return "User: {$id}, Post: {$slug}";
})->where([
    'id' => '[0-9]+',
    'slug' => '[a-z-]+'
]);

Route Groups

group(array $attributes, callable $callback): void

Create a group of routes with shared attributes.

// Prefix grouping
$router->group(['prefix' => 'admin'], function($router) {
    $router->get('/dashboard', [AdminController::class, 'dashboard']);
    $router->get('/users', [AdminController::class, 'users']);
    $router->post('/users', [AdminController::class, 'createUser']);
});

// Middleware grouping
$router->group(['middleware' => 'auth'], function($router) {
    $router->get('/profile', [ProfileController::class, 'show']);
    $router->put('/profile', [ProfileController::class, 'update']);
    $router->get('/settings', [SettingsController::class, 'index']);
});

// Namespace grouping
$router->group(['namespace' => 'App\\Controllers\\Admin'], function($router) {
    $router->get('/dashboard', 'DashboardController@index');
    $router->get('/users', 'UserController@index');
    $router->get('/posts', 'PostController@index');
});

// Combined grouping
$router->group([
    'prefix' => 'api/v1',
    'middleware' => 'api',
    'namespace' => 'App\\Controllers\\Api'
], function($router) {
    $router->get('/users', 'UserController@index');
    $router->get('/posts', 'PostController@index');
    $router->get('/comments', 'CommentController@index');
});

Route

Represents a single route with its URI, HTTP methods, action, and middleware. The Route class provides methods for configuring individual routes with names, middleware, and parameter constraints.

Route Configuration

name(string $name): Route

Give a name to the route for URL generation.

// Named route
$router->get('/users/{id}', [UserController::class, 'show'])->name('users.show');
$router->get('/posts/{slug}', [PostController::class, 'show'])->name('posts.show');
$router->post('/login', [AuthController::class, 'login'])->name('auth.login');

middleware(string|array $middleware): Route

Add middleware to the route.

// Single middleware
$router->get('/admin', [AdminController::class, 'index'])->middleware('auth');

// Multiple middleware
$router->get('/admin/users', [AdminController::class, 'users'])
    ->middleware(['auth', 'admin']);

// Middleware with parameters
$router->get('/api/users', [ApiController::class, 'users'])
    ->middleware('throttle:60,1'); // 60 requests per minute

where(string $parameter, string $constraint): Route

Add a constraint to a route parameter.

$router->get('/users/{id}', function($id) {
    return "User ID: {$id}";
})->where('id', '[0-9]+');

$router->get('/posts/{slug}', function($slug) {
    return "Post slug: {$slug}";
})->where('slug', '[a-z0-9-]+');

Route Information

getName(): ?string

Get the name of the route.

$route = $router->get('/users', [UserController::class, 'index'])->name('users.index');
$name = $route->getName(); // "users.index"

getUri(): string

Get the URI pattern of the route.

$route = $router->get('/users/{id}', [UserController::class, 'show']);
$uri = $route->getUri(); // "/users/{id}"

getAction(): mixed

Get the action of the route.

$route = $router->get('/users', [UserController::class, 'index']);
$action = $route->getAction(); // [UserController::class, "index"]

RouteCollection

Manages a collection of routes and provides methods for matching requests against registered routes. The RouteCollection handles route compilation, parameter extraction, and route matching logic.

Route Collection Management

add(Route $route): void

Add a route to the collection.

$collection = new RouteCollection();

// Create and add route
$route = new Route('GET', '/users', [UserController::class, 'index']);
$collection->add($route);

// Add named route
$route = new Route('GET', '/users/{id}', [UserController::class, 'show']);
$route->name('users.show');
$collection->add($route);

match(Request $request): ?Route

Find a matching route for the given request.

$request = new Request('GET', '/users/123');
$route = $collection->match($request);

if ($route) {
    // Route found
    $parameters = $route->parameters();
    $controller = $route->getAction();
} else {
    // No matching route
    throw new NotFoundException();
}

getByName(string $name): ?Route

Get a route by its name.

$route = $collection->getByName('users.show');
if ($route) {
    $url = $route->url(['id' => 123]);
}

Route Compilation

compile(): void

Compile all routes for faster matching.

// Add routes
$collection->add($route1);
$collection->add($route2);
$collection->add($route3);

// Compile for performance
$collection->compile();

// Now matching will be faster
$route = $collection->match($request);

URL Generation

Generate URLs for named routes with parameters. The routing system provides methods for creating URLs to named routes, making it easy to generate links in your application.

Generating URLs

url(string $name, array $parameters = []): string

Generate a URL for a named route.

// Define named routes
$router->get('/users/{id}', [UserController::class, 'show'])->name('users.show');
$router->get('/posts/{slug}/comments/{id}', [CommentController::class, 'show'])
    ->name('posts.comments.show');

// Generate URLs
$url = $router->url('users.show', ['id' => 123]); // "/users/123"
$url = $router->url('posts.comments.show', ['slug' => 'hello-world', 'id' => 456]); // "/posts/hello-world/comments/456"

route(string $name, array $parameters = []): string

Alias for url() method.

$url = $router->route('users.show', ['id' => 123]); // "/users/123"
$url = $router->route('users.index'); // "/users"

Current Route Information

current(): ?Route

Get the current matched route.

$currentRoute = $router->current();
if ($currentRoute) {
    $name = $currentRoute->getName();
    $uri = $currentRoute->getUri();
    $parameters = $currentRoute->parameters();
}

Middleware Integration

Middleware provides a convenient mechanism for filtering HTTP requests entering your application. Routes can be protected with middleware for authentication, rate limiting, and other cross-cutting concerns.

Middleware Definition

Creating Middleware

Define middleware classes that implement the middleware interface.

namespace App\Middleware;

use Forge\Http\Request;
use Forge\Http\Response;

class AuthMiddleware
{
    public function handle(Request $request, callable $next): Response
    {
        if (!$request->user()) {
            return new Response('Unauthorized', 401);
        }
        
        return $next($request);
    }
}

class RateLimitMiddleware
{
    private $maxAttempts = 60;
    private $decayMinutes = 1;
    
    public function handle(Request $request, callable $next): Response
    {
        $key = $this->resolveRequestSignature($request);
        
        if ($this->tooManyAttempts($key, $this->maxAttempts)) {
            return new Response('Too Many Attempts', 429);
        }
        
        $this->hit($key, $this->decayMinutes * 60);
        
        $response = $next($request);
        
        return $this->addHeaders($response, $key, $this->maxAttempts);
    }
    
    private function resolveRequestSignature(Request $request): string
    {
        return 'rate_limit:' . $request->ip();
    }
    
    private function tooManyAttempts(string $key, int $maxAttempts): bool
    {
        return $this->attempts($key) >= $maxAttempts;
    }
    
    private function hit(string $key, int $decaySeconds): void
    {
        // Implementation for rate limiting
    }
    
    private function attempts(string $key): int
    {
        // Implementation to get current attempts
        return 0;
    }
    
    private function addHeaders(Response $response, string $key, int $maxAttempts): Response
    {
        $response->headers['X-RateLimit-Limit'] = $maxAttempts;
        $response->headers['X-RateLimit-Remaining'] = $maxAttempts - $this->attempts($key);
        
        return $response;
    }
}

Middleware Registration

Registering Middleware

Register middleware in the application.

// In service provider or bootstrap
$container->bind('middleware.auth', AuthMiddleware::class);
$container->bind('middleware.rate_limit', RateLimitMiddleware::class);
$container->bind('middleware.cors', CorsMiddleware::class);

// Register middleware groups
$container->bind('middleware.web', [
    'middleware.cors',
    'middleware.csrf'
]);

$container->bind('middleware.api', [
    'middleware.cors',
    'middleware.rate_limit'
]);

Usage Examples

Common patterns and examples for working with the Routing system.

Basic Routing Setup

// routes.php
use Forge\Routing\Router;
use Forge\Routing\RouteCollection;

$router = new Router();
$collection = new RouteCollection();

// Define routes
$router->get('/', function() {
    return view('home');
})->name('home');

$router->get('/about', function() {
    return view('about');
})->name('about');

$router->get('/contact', function() {
    return view('contact');
})->name('contact');

// User routes
$router->get('/users', [UserController::class, 'index'])->name('users.index');
$router->get('/users/{id}', [UserController::class, 'show'])->name('users.show');
$router->get('/users/create', [UserController::class, 'create'])->name('users.create');
$router->post('/users', [UserController::class, 'store'])->name('users.store');
$router->get('/users/{id}/edit', [UserController::class, 'edit'])->name('users.edit');
$router->put('/users/{id}', [UserController::class, 'update'])->name('users.update');
$router->delete('/users/{id}', [UserController::class, 'destroy'])->name('users.destroy');

// API routes
$router->group([
    'prefix' => 'api/v1',
    'middleware' => 'api'
], function($router) {
    $router->get('/users', [ApiUserController::class, 'index']);
    $router->get('/users/{id}', [ApiUserController::class, 'show']);
    $router->post('/users', [ApiUserController::class, 'store']);
    $router->put('/users/{id}', [ApiUserController::class, 'update']);
    $router->delete('/users/{id}', [ApiUserController::class, 'destroy']);
});

Advanced Route Configuration

// Advanced routing with constraints and middleware
$router->get('/posts/{year}/{month}/{slug}', [PostController::class, 'show'])
    ->name('posts.archive')
    ->where([
        'year' => '[0-9]{4}',
        'month' => '[0-9]{2}',
        'slug' => '[a-z0-9-]+'
    ]);

// Protected routes with multiple middleware
$router->group(['middleware' => ['auth', 'verified']], function($router) {
    $router->get('/dashboard', [DashboardController::class, 'index']);
    $router->get('/profile', [ProfileController::class, 'show']);
    $router->put('/profile', [ProfileController::class, 'update']);
    
    $router->group(['prefix' => 'settings'], function($router) {
        $router->get('/', [SettingsController::class, 'index']);
        $router->put('/general', [SettingsController::class, 'updateGeneral']);
        $router->put('/security', [SettingsController::class, 'updateSecurity']);
        $router->put('/notifications', [SettingsController::class, 'updateNotifications']);
    });
});

// Admin routes with role-based middleware
$router->group([
    'prefix' => 'admin',
    'middleware' => ['auth', 'role:admin']
], function($router) {
    $router->get('/dashboard', [AdminDashboardController::class, 'index']);
    $router->resource('users', AdminUserController::class);
    $router->resource('posts', AdminPostController::class);
    $router->get('/analytics', [AnalyticsController::class, 'index']);
});

// Resource routes (RESTful)
$router->resource('posts', PostController::class);
$router->resource('comments', CommentController::class)->only(['index', 'show', 'store', 'destroy']);
$router->resource('tags', TagController::class)->except(['create', 'edit']);

URL Generation in Views

// In PHP views
Home
View User
Read Post

// In templates with helper function
Home
View User
Post

// With route helper
All Users
Create User
Edit User

// Conditional URLs
has('admin.dashboard')): ?>
    Admin Dashboard

Best Practices

Recommended patterns and guidelines for working with the Routing system.

Do's

  • • Use named routes for URL generation
  • • Group related routes with prefixes
  • • Use parameter constraints for validation
  • • Keep routes RESTful when possible
  • • Use middleware for cross-cutting concerns
  • • Document complex route patterns
  • • Use route caching in production
  • • Keep route files organized and modular

Don'ts

  • • Don't put business logic in routes
  • • Don't use too many nested parameters
  • • Don't ignore HTTP method conventions
  • • Don't create overly complex patterns
  • • Don't forget to handle 404 errors
  • • Don't use magic strings for route names
  • • Don't ignore route performance
  • • Don't create circular route dependencies