Follows PSR-7, PSR-15, and PSR-1, PSR-2, PSR-4, PSR-11, PSR-16.
Based on FastRoute, inspired by league/route.
Main ideas:
- follow PSR-7/PSR-15 or using FastRoute approach
- reversed routing (URL generation by route name)
- almost native FastRoute with possibility of using various processing strategies (CharCountBased, GroupCountBased...)
- fast multiple dispatch and reverse (with ability to add routes dynamically)
- allows using custom Loader (allows to load routes from different formats, files, etc.)
- allows caching (PSR-16)
- flexible (you can replace any component: Invoker, Dispatcher, Reverser, etc.)
- Usage without PSR-7/15 compatibility
- Usage with PSR-7/15 compatibility
- URL reverse - URL generation
- Supported types of handlers
- Supported types of Middleware
- Invoker
- Container
- Loader
- Cache
- Changes FastRoute strategies
Almost like FastRoute, but with reversed routing.
As simple as possible
$router = new Router();See other documentation sections if you need to:
- use cache
- use Loader
- change FastRoute strategy
- change reverse logic
// Add route
$router->addRoute('GET', '/test', function () {
// Route handler
}, 'test');
// Add route with name
$router->addRoute('GET', '/test/{name:[a-z]+}', function () {
// Handler for route with name
}, 'test_with_name');
// Group of routes
$router->addGroup('GET', '/api', function (Router $router) {
$router->addRoute('GET', '/users', function () {
// Handler api users
}, 'users');
}, 'api:');
$reversedRoute = $router->reverse('test_with_name', [
'name' => 'somename'
]);Same as FastRoute, see here: Basic usage FastRoute
$data = $router->dispatch('GET','/test');Router implements MiddlewareInterface, therefore it integrates into any Pipelines easily
As simple as possible
$router = new Router();See other documentation section if you need to:
- use cache
- use Loader
- change FastRoute strategy
- change reverse logic
- change Invoker strategy (processing handlers and middlewares)
Simple adding routes. The types of possible handlers are limited. Supported types of handlers.
$router->map('GET', '/test/{name:[a-z]+}', function () {
// Handler
}, 'test_with_name');Of course, you can use Middleware. Supported types of Middleware.
$router->map('POST', '/admin', function () {
// Handler
}, 'admin', [
AuthMiddleware::class,
CSRFValidationMiddleware::class
]);Groups are also supported with Middleware.
$router->group('GET', '/api', function (Router $router) {
$router->map('GET', '/users', [UsersHandlerController::class, 'all'], 'users', [
UsersGuardMiddleware::class
]);
}, 'api:', [
ApiAuthMiddleware::class
]);You can set a list of Middleware to be applied to all routes.
$router->setMiddlewares([
MyCustomMiddleware::class
]);Since the router itself is Middleware, you must call the method process to process the route.
For simple usage without any Pipeline you can use default \Phact\Router\NotFoundHandler handler.
It will throw \Phact\Router\Exception\NotFoundException if route is not found.
If route exists but requested method is not allowed,
the \Phact\Router\Exception\MethodNotAllowedException exception will be thrown.
$response = $router->process($request, new NotFoundHandler());If you added route with a name, then you can generate URL by name and provided parameters.
For example, add route:
$router->addRoute('GET', '/test/{name:[a-z]+}', 'someHandler', 'test_with_name');Then you can generate URL like this:
$url = $router->reverse('test_with_name', [
'name' => 'harry'
]);You will get /test/harry.
Provided parameters can be a simple (not assoc.) array.
In this case, the parameter substitution will be performed in order.
For example, add route:
$router->addRoute('GET', '/test/{name:[a-z]+}/{id:[0-9]+}', 'someHandler', 'test_double');Provide a simple array for URL generation:
$url = $router->reverse('test_with_name', [
'harry',
12
]);We will get /test/harry/12.
By default, unused provided parameters will be converted to query parameters.
For example, add route:
$router->addRoute('GET', '/test/{name:[a-z]+}', 'someHandler', 'test_with_name');Then, generate URL:
$url = $router->reverse('test_with_name', [
'name' => 'harry',
'faculty' => 'gryffindor'
]);We will get /test/harry?faculty=gryffindor.
Instead of method $router->reverse(...) you can apply the method $router->url(...) as they are equivalent.
If you need to define your behavior for the reverse method, then:
- Implement your own
\Phact\Router\ReverserFactory, which will create your own\Phact\Router\Reverser. - Implement your own
\Phact\Router\Reverser. - Provide your
ReverserFactoryobject to Router constructor. Like this:
$router = new Router(null, null, new MyAmazingReverserFactory());Only relevant if you use the PSR-7 compatible method of work. If you use the router in the simplest way, then you can use any type of handler.
Any of the handlers presented below must return an object \Psr\Http\Message\ResponseInterface.
Example:
$router->addRoute('GET', '/test', '\App\Handlers\MyHandler::myMethod', 'test');If Container is provided, the object will be requested from Container. If Container is not provided, the object will be created.
Example:
$router->addRoute('GET', '/test', MyInvokableHandler::class, 'test');If Container is provided, the object will be requested from Container. If Container is not provided, the object will be created.
Example:
$router->addRoute('GET', '/test', [MyHandler::class, 'myMethod'], 'test');If Container is provided, the object will be requested from Container. If Container is not provided, the object will be created.
Example:
$router->addRoute('GET', '/test', [new MyHandler(), 'myMethod'], 'test');Example:
$router->addRoute('GET', '/test', new MyInvokableHandler(), 'test');Example:
$router->addRoute('GET', '/test', function(ServerRequestInterface $request, array $variables) : ResponseInterface {
// Handler
}, 'test');To change the logic of handlers call just implement your own Invoker
Example:
$router->map('POST', '/admin', new MyInvokableHandler(), 'admin', [
ExampleMiddleware::class
]);If Container is provided, the object will be requested from Container. If Container is not provided, the object will be created.
Example:
$router->map('POST', '/admin', new MyInvokableHandler(), 'admin', [
new ExampleMiddleware()
]);Only relevant when used with Container.
Example:
$router->map('POST', '/admin', new MyInvokableHandler(), 'admin', [
'my_some_custom_middleware_from_container'
]);Invoker, which implements the handlers' and Middleware call functionality, is a replaceable part of the router.
You can replace Invoker. Just implement \Phact\Router\Invoker interface and set it to the Router like this:
$router->setInvoker(new MyCustomInvoker());If you want to use your own Container, and it will implement Psr\Container\ContainerInterface,
just set it to the router like this:
$router->setContainer($myContainer);Attention! Router just provides Container to the default Invoker implementation. If you use your own Invoker implementation, keep that in mind.
By default, Router does not use any Loader.
You can implement your own class for loading routes from your own storage (file, database, etc.).
To do that:
- implement
\Phact\Router\Loaderfor your own Loader - set your Loader to Router like this:
$router->setLoader($myCustomLoader);Method load will be called at first dispatch or reverse call.
Method load will not be called if you use Cache.
By default, Router does not use any cache.
You can use your \Psr\SimpleCache\CacheInterface (PSR-16) implementation like this:
$router->setCache($myCache);Routes are set into the cache at the time of the first data receipt (dispatch or reverse), as well as after adding a route.
Getting routes from the cache occurs on the first call of dispatch or reverse
and avoids a resource-intensive call of Loader.
You can replace any parts of Router:
- DataGenerator and Dispatcher (through DispatcherFactory)
- ReverserDataGenerator and Reverser (through ReverserFactory)
- RouteParser
By default, Router uses GroupCountBased strategy. Any other strategy can be implemented similarly to default strategy, just provide your own implementations of needed objects:
$route = new Router(
new Collector(
new MyCustomRouteParser(),
new MyCustomDataGenerator(),
new MyCustomReverserDataGenerator()
),
new MyCustomDispatcherFactory(),
new MyCustomReverserFactory()
);