Skip to content
This repository has been archived by the owner on Dec 30, 2022. It is now read-only.

bitExpert/pathfinder

Repository files navigation

bitexpert/pathfinder

A PHP routing component.

Build Status Coverage Status

Router

The router is responsible for resolving the target from the given route as well building an uri for a given route identifier (and it`s parameters). Using the Psr7Router is pretty easy:

$router = new \bitExpert\Pathfinder\Psr7Router();
$router->setRoutes(
    [
        new Route(['GET'], '/', 'index'),
        new Route(['GET'], '/question/[:title]_[:id]', 'question'),
        new Route(['GET', 'POST'], '/editquestion', 'editquestion')
    ]
);

Routes

Routes in Pathfinder are implemented immutual. You may define your routes by creating a route instance directly as shown above or using the RouteBuilder for convenience (recommended):

use bitExpert\Pathfinder\RouteBuilder;
use bitExpert\Pathfinder\Matcher\NumericMatcher;

RouteBuilder::route()
    ->get('/')
    ->to('home')
    ->build();

RouteBuilder::route()
    ->from('/user')
    ->accepting('POST')
    ->accepting('PUT')
    ->to('userAction')
    ->build();

RouteBuilder::route()
    ->get('/')
    ->to(function () {

    })
    ->named('home')
    ->build();

RouteBuilder::route()
    ->get('/user/[:userId]')
    ->to('userAction')
    ->ifMatches('userId', new NumericMatcher())
    ->build();

Customizing the RouteBuilder

In case you need some special route classes for your application, you may configure the RouteBuilder to use your custom route class instead of Route either for a particular route:

$route = RouteBuilder::route(MyCustomRoute::class)
    ->get('/')
    ->to('home')
    ->build();

$route->doCustomStuffDefinedInYourClass();

or globally as default class to use:

RouteBuilder::setDefaultRouteClass(MyCustomRoute::class);

$route = RouteBuilder::route()
    ->get('/')
    ->to('home')
    ->build();

$route->doCustomStuffDefinedInYourClass();

Matchers

Matchers are used to ensure that your route params match given criteria such as digits only:

RouteBuilder::route()
    ->get('/user/[:userId]')
    ->to('userAction')
    ->ifMatches('userId', new NumericMatcher())
    ->build();

You may add several matchers for one param, just by adding them via:

RouteBuilder::route()
    ->get('/user/[:userId]')
    ->to('userAction')
    ->ifMatches('userId', new NumericMatcher())
    ->ifMatches('userId', new MyCustomMatcher())
    ->ifMatches('userId', function ($value) {

    })
    ->build();

Middleware

You may use the BasicRoutingMiddleware to integrate Pathfinder into your PSR-7 compatible project:

use bitExpert\Pathfinder\Route;
use bitExpert\Pathfinder\Psr7Router;
use bitExpert\Pathfinder\Middleware\BasicRoutingMiddleware;

$router = new Psr7Router();
$router->addRoute(RouteBuilder::route()->get('/')->to('home')->build());

// The routing middleware will use the given router to match the request and will set the routing result as value
// of the request attribute named 'routingResult' for further use
$routingMiddleware = new BasicRoutingMiddleware($router, 'routingResult');

Errors

The Psr7Router does not throw an Exception if the request doesn't match any route. It will still return a RoutingResult returning true when calling $routingResult->failed(); You may receive the failure reason by calling $routingResult->getFailure() which will give you information about the failure reason and an optional route which could have matched, but didn't fulfill all criteria:

use bitExpert\Pathfinder\Psr7Router;
use bitExpert\Pathfinder\RouteBuilder;
use Zend\Diactoros\ServerRequest;
use bitExpert\Pathfinder\Matcher\NumericMatcher;

$router = new Psr7Router();

$homeRoute = RouteBuilder::route()
    ->get('/')
    ->to('home')
    ->build();

$orderUpdateRoute = RouteBuilder::route()
    ->put('/order/[:orderId]')
    ->to('updateOrder')
    ->ifMatches('id', new NumericMatcher())
    ->build();
 
$router->setRoutes([$homeRoute, $orderUpdateRoute]);


// Not found example
$request = new ServerRequest([], [], '/users', 'GET');
$result = $router->match($request);

$result->failed(); // -> true
$result->getFailure(); // -> RoutingResult::FAILED_NOT_FOUND
$result->hasRoute(); // -> false
 
// Method not allowed example
$request = new ServerRequest([], [], '/order/1', 'GET');
$result = $router->match($request);

$result->failed(); // -> true
$result->getFailure(); // -> RoutingResult::FAILED_METHOD_NOT_ALLOWED
$result->hasRoute(); // -> true
$result->getRoute(); // -> $orderUpdateRoute
 
 
// BadRequest example
$request = new ServerRequest([], [], '/order/abc', 'PUT');
$result = $router->match($request);

$result->failed(); // -> true
$result->getFailure(); // -> RoutingResult::FAILED_BAD_REQUEST
$result->hasRoute(); // -> true
$result->getRoute(); // -> $orderUpdateRoute

License

Pathfinder is released under the Apache 2.0 license.