Fastroute

PSR-15 FastRoute router middleware for BitFrame microframework

Releases

{
    "require": {
		"designcise/bitframe-fastroute": "^1.0"
	}
}

Install

Add the following as a dependency in your project's composer.json:

"designcise/bitframe-fastroute": "^1.0"

Getting Started →

use \BitFrame\Router\FastRouteRouter;

require 'vendor/autoload.php';

$app = new \BitFrame\Application;

// instantiation with default options
$router = new FastRouteRouter;// lazy instantiation with default options
$router = FastRouteRouter::class;

$app->run([
    /* \BitFrame\Message\DiactorosResponseEmitter::class, */
    // router should normally be the last middleware to run
    $router
]);

Getting Started

You can create a new instance of \BitFrame\Router\FastRouteRouter simply by using the new keyword.

You can also do lazy instantiation, if it's supported by your middleware dispatcher, by just providing the class name with its namespace, or simply by appending ::class to an object instance or class name.

You can access the \FastRoute\RouteCollector instance by calling the getRouter() method on a BitFrame\Router\FastRouteRouter instance.

← Install Defining Routes →

use \BitFrame\Router\RouteCollectionInterface;
use \BitFrame\Router\FastRouteRouter;

require 'vendor/autoload.php';

$app = new \BitFrame\Application;

$router = new FastRouteRouter;

/**
 * Add a route to the map.
 *
 * @param array|string $method
 * @param string $path
 * @param string|callable $handler
 */
$app->map(['GET', 'POST'], '/test', function ($request, $response, $next) {
    $response->getBody()->write('Test Page');
    
    return $response;
});/**
 * Add a route that responds to GET HTTP method.
 *
 * @param string $path
 * @param string|callable $handler
 */
$app->get('/test', function ($request, $response, $next) {
    $response->getBody()->write('Test Page');
    
    return $response;
});/**
 * Add a route that responds to POST HTTP method.
 *
 * @param string $path
 * @param string|callable $handler
 */
$app->post('/test', function ($request, $response, $next) {
    $response->getBody()->write('Test Page');
    
    return $response;
});/**
 * Add a route that responds to PUT HTTP method.
 *
 * @param string $path
 * @param string|callable $handler
 */
$app->put('/test', function ($request, $response, $next) {
    // ...
    
    return $response;
});/**
 * Add a route that responds to PATCH HTTP method.
 *
 * @param string $path
 * @param string|callable $handler
 */
$app->patch('/test', function ($request, $response, $next) {
    // ...
    
    return $response;
});/**
 * Add a route that responds to DELETE HTTP method.
 *
 * @param string $path
 * @param string|callable $handler
 */
$app->delete('/test', function ($request, $response, $next) {
    // ...
    
    return $response;
});/**
 * Add a route that responds to HEAD HTTP method.
 *
 * @param string $path
 * @param string|callable $handler
 */
$app->head('/test', function ($request, $response, $next) {
    // ...
    
    return $response;
});/**
 * Add a route that responds to OPTIONS HTTP method.
 *
 * @param string $path
 * @param string|callable $handler
 */
$app->options('/test', function ($request, $response, $next) {
    // ...
    
    return $response;
});// matches /user/42, but not /user/xyz
$app->get('/user/{id:\d+}', function($request, $response, $next) {
    $id = $request->getattribute('id');

    return $response;
});

// matches /user/foobar, but not /user/foo/bar
$app->get('/user/{name}', 'SomeController::someMethod');

// matches /user/foo/bar as well
$app->get('/user/{name:.+}', 'SomeController::someMethod');$app->group('/admin', function (RouteCollectionInterface $r) {
    function handler($request, $response, $next) {
        $response->getBody()->write('Admin Page');
        return $response;
    }

    $r->get('/do-something', 'handler');
    $r->get('/do-another-thing', 'handler');
    $r->get('/do-something-else', 'handler');
});

$app->run([
    /* \BitFrame\Message\DiactorosResponseEmitter::class, */
    // router should normally be the last middleware to run
    $router
]);

Defining Routes

Routes are defined by calling one of the following methods on the \BitFrame\Application or \BitFrame\Router\FastRouteRouter instance:

  1. map($method, $path, $handler): \BitFrame\Router\Route
  2. get($path, $handler): \BitFrame\Router\Route
  3. post($path, $handler): \BitFrame\Router\Route
  4. put($path, $handler): \BitFrame\Router\Route
  5. patch($path, $handler): \BitFrame\Router\Route
  6. delete($path, $handler): \BitFrame\Router\Route
  7. head($path, $handler): \BitFrame\Router\Route
  8. options($path, $handler): \BitFrame\Router\Route

The $handler parameter does not necessarily have to be a callback, it could also be a controller class/function name. FastRoute only tells you which handler corresponds to your URI, how you interpret it is up to you.

Routes with an endpoint enclosed within {} specify a placeholder, for example {foo} specifies a placeholder with name foo matching the regex [^/]+. To adjust the pattern the placeholder matches, you can specify a custom pattern, for example {foo:[0-9]+}.

Read More…

Custom patterns for route placeholders cannot use capturing groups. For example {lang:(en|de)} is not a valid placeholder, because () is a capturing group. Instead you can use either {lang:en|de} or {lang:(?:en|de)}.

Parts of the route enclosed in [...] are considered optional, so that /foo[bar] will match both /foo and /foobar. Optional parts are only supported in a trailing position, not in the middle of a route.

All routes defined inside a group have a common prefix.

← Getting Started Controllers →

use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;
use \Psr\Http\Server\RequestHandlerInterface as Handler;
use \Psr\Http\Server\MiddlewareInterface;use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;use \Psr\Http\Message\ServerRequestInterface;
use \Psr\Http\Message\ResponseInterface;
use \Psr\Http\Server\RequestHandlerInterface;use \BitFrame\Router\FastRouteRouter;

require 'vendor/autoload.php';

$router = new FastRouteRouter;

/* 1: define controller class */

// 2: define route
$router->get('/some/route-1', 'SomeController::someMethod');
$router->get('/some/route-2', [new SomeController, 'someMethod']);
/* 1: define controller class */

// 2: define route
$router->get('/some/route', new SomeController);
// define route
$router->get('/', new class implements MiddlewareInterface {
    public function process(
        Request $request, 
        Handler $handler
    ): Response 
    {
        $response = $handler->handle($request);
        $response->getBody()->write("Hello World!");

        return $response;
    }
});
/* 1: define controller class */

// 2: define route
$router->get('/some/route', new SomeController);
// define route
$router->get('/', function (
    Request $request, 
    Response $response, 
    callable $next
) {
    $response->getBody()->write('Hello World!');
    return $response;
});
// 1: define controller function
function controller(
    Request $request, 
    Response $response, 
    callable $next
) {
    $response->getBody()->write('Hello World!');
    return $response;
}

// 2: define route
$router->get('/some/route', 'controller');
// define route
$router->get('/some/route', [new class {
    public function someMethod(
        ServerRequestInterface $request, 
        RequestHandlerInterface $handler
    ): ResponseInterface 
    {
        $response = $handler->handle($request);
        $response->getBody()->write('Hello World!');

        return $response;
    }
}, 'someMethod']);

Controllers

A controller (any callable) may be used to handle routes. Below are some of the ways a controller can be assigned using either \BitFrame\Application or \BitFrame\Router\FastRouteRouter instance:

  • Named Class Method
  • Anonymous Class With Named Class Method
  • Class Implementing MiddlewareInterface
  • Anonymous Class Implementing MiddlewareInterface
  • Magic __invoke
  • Anonymous Function
  • Named Function

See our guide on how to handle routes for more examples and further explanation. To find out how to pass arguments/params to a controller, see our guide on sharing data.

← Defining Routes Route Middleware →

use \BitFrame\Router\FastRouteRouter;

require 'vendor/autoload.php';

$app = new \BitFrame\Application;

$router = new FastRouteRouter;

$app->get('/some/route', function($request, $response, $next) {
    /* // run router middleware before  */
    
    // run router middleware after
    $response->getBody()->write('Router Handler;');
    return $next($request, $response);
});
/* 1: define controller class */

// 2: define route
$app->get('/some/route', 'SomeController::runMiddlewareBefore');

$router->addMiddleware(function($request, $response, $next) {
    $response->getBody()->write('First Router Middleware;');
	return $next($request, $response);
});

$router->addMiddleware(function($request, $response, $next) {
    $response->getBody()->write('Second Router Middleware;');
	return $response;
});

$app->run([
    /* \BitFrame\Message\DiactorosResponseEmitter::class, */
    // router should normally be the last middleware to run
    $router
]);

Route Middleware

The router handler function itself is added as the first middleware to be executed in a route middleware queue. Therefore, a router handler must make a call to the next middleware (for example by using $next($request, $response) or $handler->handle($request)) to run the next middleware (if any) in queue.

  • Router middleware (single or an array of middlewares) can only be added to the \BitFrame\Router\FastRouteRouter instance using the addMiddleware method since it has its own middleware dispatcher and queue.
  • You could use any controllers as the handler for router or router middleware (as discussed in the previous section).

← Controllers About →

/**
 * FastRoute Router Wrapper (PSR-15 / PSR-7 compatible)
 *
 * @author    
 * @copyright Copyright (c) 2017-2018 Daniyal Hamid (https://designcise.com)
 *
 * @license   MIT License
 */

About

FastRoute Router helps you define and manage your web project's routes.

FastRoute Official GitHub

← Route Middleware API →

Comments

Let us know if you have something to say or add

Changelog

Latest version 1.0.0 released on Feb 14, 2018

Version 1.0.4

Version 1.0.3

Version 1.0.2

  • Added url normalization support which fixes the document root when the document root directive has not been explicitly declared for the project folder (such as by using the DOCUMENT_ROOT directive in apache)
  • Added url normalization to the FastRouteRouter::process() method

Version 1.0.1

  • Fixed reference to RouteCollectionInterface
  • Added main BitFrame package dependency

Version 1.0.0

  • Methods that don't exist in wrapper class delegate to FastRoute class
  • PSR-15 & PSR-7 support
  • Support to specify router-specific middleware
  • The route's callback itself acts as a middleware