Маршрутизація
Ядро використовує
League Route —
не власний router. Навіщо: зрілий match / groups / middleware,
PSR-7/15, без дублювання в Concept. Файли маршрутів підключає
HttpKernelServiceProvider через require; у файлі
доступна змінна $router (League\Route\Router).
HTTP surface тримаємо окремими файлами, а не в Bootstrap: URL → handler і списки middleware видно без читання контейнера. Інакше «що відбувається на /contact» довелося б збирати з кількох місць.
Підключення файлів
Шляхи — абсолютні й явні. Ядро не шукає routes/ за
конвенцією: хто збирає додаток, той і передає список. Якщо файлу
немає — одразу InvalidArgumentException, а не «тихий»
порожній Router.
new HttpKernelServiceProvider(
routePaths: [
__DIR__ . '/../routes/web.php',
__DIR__ . '/../routes/api.php',
],
resolvers: [...],
);
Файл маршрутів
Мінімум: HTTP-метод, path, handler. Ім’я через setName —
коли знадобиться interceptors, URL generator (у Http extension)
або посилання з коду без хардкоду path.
<?php declare(strict_types=1);
use App\PingHandler;
use League\Route\Router;
/** @var Router $router */
$router->get('/ping', [PingHandler::class, 'ping'])->setName('ping');
$router->get('/hello/{name}', [PingHandler::class, 'hello']);
Handlers
League Route резолвить class-string з контейнера — тому constructor injection працює без «new» у route file. Три форми:
[Class::class, 'method']— handler з DIClosure— коли логіка справді одноразова- Invokable object —
__invoke
Handler повинен повертати ResponseInterface.
Інакше RouteStrategy кине RuntimeException —
краще fail рано, ніж «щось» у body без Content-Type.
Параметри URL
Плейсхолдери {name} стають ключами в
$route->getVars() і attributes enriched request.
Ім’я плейсхолдера має збігатися з іменем параметра handler-а —
саме так RouteParameterArgumentResolver знаходить
значення без анотацій. Коли потрібен int/UUID з casting —
це вже extension-resolver у chain, не зміна router-а.
Групи та middleware
Група — коли спільний префікс і/або той самий middleware-ланцюжок (API auth, HTML CSRF). Не вішайте HTML-middleware на JSON-групу «про запас»: поведінка запиту має бути очевидною з route file. Middleware — PSR-15, див. Middleware.
use League\Route\RouteGroup;
$router->group('/api', function(RouteGroup $router): void {
$router->get('/status', [StatusHandler::class, 'show']);
})->lazyMiddlewares([AuthMiddleware::class]);
Іменовані маршрути
->setName('ping') — ім’я доступне через
$route->getName() у interceptors і власній логіці.
Коли: ACL за іменем, генерація URL, тести. Коли ні: одноразові
ping-маршрути без посилань — ім’я можна не ставити.