Routing
Router s explicitními a convention routes, named URL generation, route groups a middleware stack.
Overview
Routes are loaded during kernel bootstrap from app/Config/Routing.php via Framework::routesFromFile(...). Router stores explicit route definitions and also supports convention fallback resolution for GET/HEAD when no explicit route matches.
Route definition file
Routing file must return callable(Router $router): void.
<?php
declare(strict_types=1);
use Lemonade\Framework\Routing\Router;
return static function (Router $router): void {
$router->getNamed('home', '/', 'HomeController@index');
};
HTTP methods
Router supports get, post, put, patch, delete, head, options and named variants (getNamed, postNamed, ...). Generic map/mapNamed is also available.
$router->get('/contact', 'ContactController@index');
$router->post('/contact', 'ContactController@submit');
$router->options('/contact', 'ContactController@options');
Handler syntax
Handler must use Controller@action string. Router resolves controller class via configured namespace (App\Controllers by default). Fully-qualified controller class names are supported.
$router->get('/docs', 'DocumentationController@index');
$router->get('/api/ping', '\App\Controllers\Api\PingController@show');
Named routes
Named routes are unique. You can define name inline via ->name(...) or use getNamed/postNamed shortcuts.
// 1) Basic named route
$router->getNamed('home', '/', 'HomeController@index');
// 2) Route with parameter + chained name
$router
->get('/articles/{id}', 'ArticleController@detail')
->name('article.detail');
Route parameters
Standard path parameters use {name} placeholders and are passed to controller action via route match parameters.
$router
->get('/articles/{id}', 'ArticleController@detail')
->name('article.detail');
URL generation
RoutingServiceProvider registers UrlGenerator and alias url for explicit container wiring. In controllers use $this->url(), in services inject UrlGenerator, and in views use $helpers->url() / $helpers->localizedUrl(). route(name, params) replaces placeholders and appends extra params as query string.
// 3) Controller URL generation
$url = $this->url()->route('article.detail', ['id' => 123]);
// 4) Extra query params
$url = $this->url()->route('article.detail', [
'id' => 123,
'preview' => 1,
]);
// Result: /articles/123?preview=1
Route groups
group(prefix, builder) prefixes all nested routes and returns RouteGroup. Group middleware can be attached to all routes through RouteGroup::middleware(...).
// 5) Route group
$router->group('/admin', static function (Router $router): void {
$router->getNamed('dashboard', '/dashboard', 'Admin\DashboardController@index');
});
Localized groups
localizedGroup(builder) registers both non-localized routes and localized variants. Localized variant uses route prefix with locale placeholder and localized name prefix (configured through localization URL config).
// 6) Localized group
$router->localizedGroup(static function (Router $router): void {
$router->getNamed('home', '/', 'HomeController@index');
});
Route middleware
Route-specific middleware is supported on Route and RouteGroup. Middleware definitions are class-strings implementing MiddlewareInterface and are resolved from container in DispatchRequestHandler.
// 7) Route-specific middleware
$router
->get('/admin/profile', 'Admin\ProfileController@index')
->middleware(App\Middleware\Admin\AdminAuthMiddleware::class);
$router->group('/admin', static function (Router $router): void {
$router->get('/dashboard', 'Admin\AdminDashboardController@index');
})->middleware(App\Middleware\Admin\AdminAuthMiddleware::class);
Dispatch integration
DispatchRequestHandler performs Router::match($request), creates ControllerRequestHandler, wraps it with matched route middleware pipeline, and executes it. ControllerResolver then resolves controller instance, action args (including route params) and normalizes action result to PSR response.
Convention fallback
If no explicit route matches GET/HEAD, router attempts convention resolution: / -> HomeController@index; otherwise it tries SegmentController@index or last-segment-as-action pattern. Use explicit named routes for stable public endpoints.