apinephp / dist-route
A lightweight regular expression based request router with support for dependency injection
Requires
- php: >=7.2
- apinephp/resolver: ^1.3
- psr/container: ^1.0
- psr/http-message: ^1.0
- psr/http-server-handler: ^1.0
- psr/http-server-middleware: ^1.0
Requires (Dev)
- phpunit/phpunit: ^7
- pimple/pimple: ^3.2
- vimeo/psalm: ^2.0
This package is auto-updated.
Last update: 2024-10-18 08:15:25 UTC
README
A lightweight regular expression based request router with support for dependency injection targeted at projects consuming the recommendations of the PHP-FIG.
Main Features
- Named parameters in patterns
- Optional parameters
- Subrouting
- Support for
GET
,POST
,DELETE
,PUT
,OPTIONS
,HEAD
,TRACE
, and custom request methods - Dependency injection
- Middlewares
- Full compatibility with PSR-7 HTTP Message Interface, PSR-11 Container Interface and PSR-15 HTTP Handlers
Installation
Installation is made with composer
composer require apinephp/dist-route
The package requires PHP 7.2 or newer.
Usage Example
<?php
require '/path/to/vendor/autoload.php';
use Apine\DistRoute\Router;
$router = new Router($container);
$router->use($middleware);
$router->map(['GET'], '/users', UserController::class . '@all');
$router->get('/user/{id:(\d+)}', UserController::class . '@one');
$response = $router->handle($serverRequest);
Define a route
Routes are defined by calling the mapping methods of the router like map()
:
$router->map($methods, $pattern, $handler);
The $methods
is a list of one or many uppercase HTTP methods for which a route should match.
The $pattern
defines a placeholder for matching using the syntax {name}
which creates a placeholder named name
. It is possible to change the regex pattern which a placeholder matches by writing the regex after the name and a colon. It is also possible to mark a placeholder as optional by adding a question mark (?
) before its name.
$router->map(['GET'], '/user/{id}', 'handler');
$router->map(['GET'], '/user/{id:(\d+)}', 'handler');
$router->map(['GET'], '/user/{?id}', 'handler');
The $handler
parameter is the handler that should be executed if the route matches a ServerRequest. It may be an instance of MiddlewareInterface
, a Closure
, the name of a function, or the fully qualified name of a class and the name of a method separated by a @
. The handler must return a ResponseInterface
.
Shorthand methods
The router has shorthand methods for the following request methods : GET
, POST
, DELETE
, PUT
, OPTIONS
, HEAD
, and TRACE
.
Prefixed Routes (Subrouting)
The group()
method allows to define multiple routes under a common prefix pattern. The $pattern
parameter is a pattern as define above that will be prefixed to the child routes. The $closure
parameter is a function called within the context of the router. It must receive as its only parameter an instance of RouterInterface
which represents the current router.
The following will have the same effect as the example above:
$router->group('/user', function (RouterInterface $mapper) {
$mapper->map(['GET'], '/{id}', 'handler');
$mapper->map(['GET'], '/{id:(\d+)}', 'handler');
$mapper->map(['GET'], '/{?id}', 'handler');
});
Using middlewares
A middleware is added to the router using the use()
method. The middleware should be an instance of MiddlewareInterface
as defined in the PSR-15 HTTP Handlers recommendation from the PHP-FIG. The middleware will be applied to all the requests being treated regardless a matching route is found or not.
$router->use($middleware);
Dispatching (handling) a request
A request is handled by calling the handle()
method of the router. The method accepts an instance of ServerRequestInterface
.
The method throws an RouteNotFoundException
if none of the routes matched the request. Otherwise, it returns the instance of ResponseInterface
from the handler.
Execution priority
Routes and middlewares are seeked through in the order at which they were registered in the router. It works like a queue.
Let's say you registered a route then a middleware in the following fashion:
$router->get('/test/{number:([0-9]+)}', 'routeFunction');
$router->use($middleware);
It this example, the router will first try to match the route to the request it receives. If it matches, the router will execute the callable of the route then return its result. Otherwise, it will execute to the middleware.
Hence it is a great idea to define the middlewares first then define routes.