mj-zana / routing
Routes, groups, attribute routes, URL generation and controller dispatch for Zana applications
Requires
- php: ^8.5
- mj-zana/http: ^2.4
Requires (Dev)
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^11.5
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-27 16:29:41 UTC
README
Routes, groups, attribute routes, URL generation and controller dispatch, on
top of mj-zana/http. Requires PHP 8.5 or later.
composer require mj-zana/routing
Usage
Register HttpServiceProvider and RoutingServiceProvider, register your
controllers as services, and add routes in a module's boot():
public function register(ServiceCollectionInterface $services): void { $services->transient(PatientController::class); } public function boot(ContainerInterface $container): void { $router = $container->get(Router::class); $router->get('/patients/{id:\d+}', [PatientController::class, 'show'])->name('patients.show'); $router->group('/api', function (Router $r) { $r->post('/bmi', CalculateBmiAction::class); }, middleware: [AuthenticationMiddleware::class]); $router->loadAttributes(MeasurementController::class); }
#[Route('/measurements', middleware: [AuthenticationMiddleware::class])] final class MeasurementController { public function __construct(private MeasurementRepository $measurements) {} #[Route('/{id:\d+}', name: 'measurements.show')] public function show(int $id): array // route parameters are converted to int, float or bool { return $this->measurements->get($id)->toArray(); // arrays and objects become JSON } }
$urls->generate('patients.show', ['id' => 7], ['tab' => 'history']); // /patients/7?tab=history
- Dispatch:
- Handlers are called through the request scope, so their dependencies and
route parameters are injected, and a parameter typed
ServerRequestInterfacereceives the request. - Return values become responses:
nullbecomes 204, a string becomes HTML, arrays and objects become JSON.
- Handlers are called through the request scope, so their dependencies and
route parameters are injected, and a parameter typed
- Errors: unknown paths are 404, and wrong methods are 405 with an
Allowheader. - Caching:
Router::export()/Router::fromExport()cache the route table (closures can't be exported).
New in 2.1
$router->localized(['en' => '/about', 'fr' => '/a-propos'], [PageController::class, 'about'])->name('about'); $urls->generate('about'); // the current request's locale $urls->generate('about', ['_locale' => 'fr']); // /fr/a-propos $urls->alternates('about'); // ['en' => '/en/about', 'fr' => '/fr/a-propos']
- Route defaults become request attributes, such as
_locale. - Result converters, services tagged
routing.result_converters, turn custom results into responses.
New in 2.2 and 2.3
-
Route metadata (2.2):
->meta([...])or#[Route(meta: [...])], kept in the route cache. -
Redirect routes (2.3): old URLs and shortcuts, still exportable to the route cache:
$router->redirect('/about-us', 'about', parameters: ['_locale' => 'fr']); // 301 to a route $router->redirect('/news/{slug}', 'blog.show'); // the slug carries over $router->redirect('/webmail', 'https://mail.example.com', 302, ['Cache-Control' => 'no-store']);
The target is a route name, a path or an http(s) URL fixed in code; protocol-relative URLs, other schemes and headers with line breaks are refused.
License
MIT — see LICENSE.