Skip to content

Routing ​

Lalaz provides a powerful and expressive routing system. Routes are defined in files inside the routes/ directory and are automatically loaded based on your configuration.

Defining Routes ​

Routes are defined in a route file that returns a closure receiving a Router instance:

php
<?php declare(strict_types=1);

use Lalaz\Web\Routing\Router;

return function (Router $router): void {
    $router->get('/', fn() => ['message' => 'Hello, World!']);
};

Basic Routes ​

The router provides methods for all standard HTTP verbs:

php
$router->get('/users', UserController::class . '@index');
$router->post('/users', UserController::class . '@store');
$router->put('/users/{id}', UserController::class . '@update');
$router->patch('/users/{id}', UserController::class . '@update');
$router->delete('/users/{id}', UserController::class . '@destroy');
$router->options('/users', UserController::class . '@options');
$router->head('/users', UserController::class . '@head');

Any Method ​

Register a route that responds to any HTTP method:

php
$router->any('/webhook', WebhookController::class . '@handle');

Multiple Methods ​

Register a route for specific HTTP methods:

php
$router->methods(['GET', 'POST'], '/form', FormController::class . '@handle');

Route Parameters ​

Required Parameters ​

Use curly braces to define route parameters:

php
$router->get('/users/{id}', function (Request $request): array {
    $id = $request->routeParam('id');
    return ['user_id' => $id];
});

$router->get('/posts/{postId}/comments/{commentId}', function (Request $request): array {
    $postId = $request->routeParam('postId');
    $commentId = $request->routeParam('commentId');
    return ['post' => $postId, 'comment' => $commentId];
});

Parameter Patterns ​

Add regex constraints to parameters:

php
// Only numeric IDs
$router->get('/users/{id:\d+}', UserController::class . '@show');

// Alphanumeric slugs
$router->get('/posts/{slug:[a-z0-9-]+}', PostController::class . '@show');

// Catch-all path
$router->get('/files/{path:.+}', FileController::class . '@serve');

Route Handlers ​

Routes accept several handler formats:

Closure Handlers ​

php
$router->get('/health', function (): array {
    return ['status' => 'ok', 'timestamp' => date('c')];
});

Controller String Syntax ​

php
$router->get('/users', UserController::class . '@index');
$router->get('/users/{id}', 'App\Controllers\UserController@show');

Controller Array Syntax ​

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

Route Groups ​

Group routes with shared attributes like prefixes and middleware:

Simple Prefix ​

php
$router->group('/api', function (Router $router): void {
    $router->get('/users', UserController::class . '@index');     // /api/users
    $router->get('/posts', PostController::class . '@index');     // /api/posts
});

With Attributes Array ​

php
$router->group([
    'prefix' => '/admin',
    'middleware' => [AuthMiddleware::class, AdminMiddleware::class]
], function (Router $router): void {
    $router->get('/dashboard', AdminController::class . '@dashboard');
    $router->get('/users', AdminController::class . '@users');
});

Nested Groups ​

php
$router->group('/api', function (Router $router): void {
    $router->group('/v1', function (Router $router): void {
        $router->get('/users', UserControllerV1::class . '@index');  // /api/v1/users
    });
    
    $router->group('/v2', function (Router $router): void {
        $router->get('/users', UserControllerV2::class . '@index');  // /api/v2/users
    });
});

Resource Routes ​

The resource() method registers standard RESTful routes for a controller:

php
$router->resource('users', UserController::class);

This creates the following routes:

MethodPathActionDescription
GET/usersindexList all users
GET/users/createcreateShow create form
POST/usersstoreCreate a user
GET/users/showShow a user
GET/users/{userId}/editeditShow edit form
PUT/users/updateUpdate a user
PATCH/users/updatePartial update
DELETE/users/destroyDelete a user

Parameter Naming

The parameter name is derived from the resource name in singular form. For users, the parameter is userId. For posts, it would be postId.

Partial Resources ​

Use only or except to limit which routes are registered:

php
// Only these actions
$router->resource('users', UserController::class, only: ['index', 'show']);

// All except these actions (useful for APIs without HTML forms)
$router->resource('users', UserController::class, except: ['create', 'edit']);

Attribute-Based Routing ​

Define routes directly on controller methods using PHP 8 attributes:

php
<?php

declare(strict_types=1);

namespace App\Controllers;

use Lalaz\Web\Routing\Attribute\Route;

class UserController
{
    #[Route('/users', method: 'GET')]
    public function index(): array
    {
        return ['users' => []];
    }

    #[Route('/users/{id}', method: 'GET')]
    public function show(int $id): array
    {
        return ['user' => ['id' => $id]];
    }

    #[Route('/users', method: 'POST', middlewares: ['auth'])]
    public function store(): array
    {
        return ['message' => 'User created'];
    }
}

Register Controllers ​

Register controllers with attribute routes in your configuration:

php
// config/app.php
return [
    'router' => [
        'controllers' => [
            App\Controllers\UserController::class,
            App\Controllers\PostController::class,
        ],
    ],
];

Or register them manually:

php
$router->registerControllers([
    App\Controllers\UserController::class,
    App\Controllers\PostController::class,
]);

Route Attribute Options ​

php
#[Route(
    path: '/users/{id}',           // URL path (required)
    method: 'GET',                  // Single HTTP method
    methods: ['GET', 'HEAD'],       // Multiple HTTP methods
    middlewares: ['auth', 'log']    // Middleware to apply
)]

Route Middleware ​

Apply middleware to individual routes:

php
$router->get('/admin', AdminController::class . '@index', [
    AuthMiddleware::class,
    AdminMiddleware::class
]);

Or to a group:

php
$router->group([
    'prefix' => '/admin',
    'middleware' => [AuthMiddleware::class]
], function (Router $router): void {
    // All routes here require authentication
    $router->get('/dashboard', AdminController::class . '@dashboard');
});

Route Configuration ​

Routes are configured in config/app.php:

php
return [
    'router' => [
        // Route files to load
        'files' => [
            __DIR__ . '/../routes/api.php',
            __DIR__ . '/../routes/web.php',
        ],
        
        // Controllers with attribute routes
        'controllers' => [
            App\Controllers\UserController::class,
        ],
    ],
];

Inspecting Routes ​

Use the CLI to list all registered routes:

bash
php lalaz routes:list

Validate route definitions:

bash
php lalaz routes:validate

Route Caching ​

For production, cache your routes for better performance:

bash
# Generate route cache
php lalaz route:cache

# Clear route cache
php lalaz route:cache:clear

WARNING

Remember to clear the route cache after making changes to your route files.

Released under the MIT License.