How To

Learn how to handle routes in BitFrame Microframework

Handle Routes

Using A Named Class Method

You could specify a custom class method to call when the middleware executes using one of the following formats:

  1. 'ClassName::methodName': lazy instantiate the object;
  2. [Object, 'methodName']: pre-instantiate the object.

For example:

require '../vendor/autoload.php';

$app = new \BitFrame\Application;

/* 1: define controller class */

// 2: define route
$app->get('/hello/{name}', 'SomeController::someMethod');
$app->get('/hello/{name}', [new SomeController, 'someMethod']);

$app->run([
    \BitFrame\Message\DiactorosResponseEmitter::class,
    \BitFrame\Router\FastRouteRouter::class
]);

If instantiating your route controller class does not require any arguments to be supplied, then you may want to use the lazy instantiation method as it may be good for performance.

Anonymous Class With Named Class Method

PHP 7+ allows us to create anonymous classes. If you wanted to can call a specific class method in an anonymous class (when the route is handled), you could do so by using the format: [@AnonymousClass, 'methodName'] like so:

use \Psr\Http\Message\ServerRequestInterface;
use \Psr\Http\Message\ResponseInterface;
use \Psr\Http\Server\RequestHandlerInterface;

require '../vendor/autoload.php';

$app = new \BitFrame\Application;

// define route
$app->get('/hello/{name}', [new class {
    public function someMethod(
        ServerRequestInterface $request, 
        RequestHandlerInterface $handler
    ): ResponseInterface 
    {
        $name = $request->getAttribute('name');
        
        $response = $handler->handle($request);
        $response->getBody()->write("Hello, $name");

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

$app->run([
    \BitFrame\Message\DiactorosResponseEmitter::class,
    \BitFrame\Router\FastRouteRouter::class
]);

Using A MiddlewareInterface Instance

A route itself can be treated as a middleware (i.e. if the router you're using implements such functionality — for example \BitFrame\Router\FastRouteRouter). In such instances, a router handler class must implement \Psr\Http\Server\MiddlewareInterface so that when the router middleware (including the route itself) is processed (as per the PSR-15 spec) the process() method is automatically called, for example:

require '../vendor/autoload.php';

$app = new \BitFrame\Application;

/* 1: define controller class */

// 2: define route
$app->get('/hello/{name}', new SomeController);

$app->run([
    \BitFrame\Message\DiactorosResponseEmitter::class,
    \BitFrame\Router\FastRouteRouter::class
]);
Anonymous Class

In PHP 7+, you could use anonymous classes implementing \Psr\Http\Server\MiddlewareInterface like so:

use \Psr\Http\Message\ServerRequestInterface;
use \Psr\Http\Message\ResponseInterface;
use \Psr\Http\Server\RequestHandlerInterface;
use \Psr\Http\Server\MiddlewareInterface;

require '../vendor/autoload.php';

$app = new \BitFrame\Application;

// define route
$app->get('/hello/{name}', new class implements MiddlewareInterface {
	public function process(
		ServerRequestInterface $request, 
		RequestHandlerInterface $handler
	): ResponseInterface 
	{
		$name = $request->getAttribute('name');
		
		$response = $handler->handle($request);
		$response->getBody()->write("Hello, $name");

		return $response;
	}
});

$app->run([
    \BitFrame\Message\DiactorosResponseEmitter::class,
    \BitFrame\Router\FastRouteRouter::class
]);

Using The Magic __invoke

require '../vendor/autoload.php';

$app = new \BitFrame\Application;

/* 1: define controller class */

// 2: define route
$app->get('/hello/{name}', new SomeController);

$app->run([
    \BitFrame\Message\DiactorosResponseEmitter::class,
    \BitFrame\Router\FastRouteRouter::class
]);

Using Functions

Anonymous Functions:
use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;

require '../vendor/autoload.php';

$app = new \BitFrame\Application;

// define route
$app->get('/hello/{name}', function (Request $request, Response $response, callable $next) {
    $name = $request->getAttribute('name');
    $response->getBody()->write("Hello, $name");
    return $response;
});

$app->run([
    \BitFrame\Message\DiactorosResponseEmitter::class,
    \BitFrame\Router\FastRouteRouter::class
]);
Named Functions:
use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;

require '../vendor/autoload.php';

$app = new \BitFrame\Application;

// 1: define controller function
function controller(Request $request, Response $response, callable $next) {
    $name = $request->getAttribute('name');
    $response->getBody()->write("Hello, $name");
    return $response;
}

// 2: define route
$app->get('/hello/{name}', 'controller');

$app->run([
    \BitFrame\Message\DiactorosResponseEmitter::class,
    \BitFrame\Router\FastRouteRouter::class
]);

Recommendation

We recommend you use named class methods, because:

  • Using a MiddlewareInterface instance would only work if the router you're using supports running the route as a middleware;
  • The magic __invoke and using functions may lead to issues with typehinting because $next as callable is not type safe as there's no way of ensuring that the callable is actually able to accept the arguments passed to it.

Comments

Let us know if you have something to say or add