The Hooks of React Router

If you’re looking to get started with React Router – or looking to migrate away from version 4 – this article on CSS-Tricks will introduce to it and its hooks:

React Router 5 embraces the power of hooks and has introduced four different hooks to help with routing. You will find this article useful if you are looking for a quick primer on the new patterns of React Router.

The Hooks of React Router →

bramus/router Updates

It’s been 4 months since I released bramus/router, the lightweight and object oriented PHP Router I wrote. Since then a few new features worth mentioning were added.

Subrouting Support

It’s now possible to mount several routes onto a base route. Think of creating a /movies route on which you attach a callable which in its turn adds subroutes onto the base route. The result is that all subroutes will get prefixed with that base route:

// Create a Router
$router = new \Bramus\Router\Router();

// Subrouting
$router->mount('/movies', function() use ($router) {

	// will result in '/movies'
	$router->get('/', function() {
		echo 'movies overview';
	});

	// will result in '/movies'
	$router->post('/', function() {
		echo 'add movie';
	});

	// will result in '/movies/id'
	$router->get('/(\d+)', function($id) {
		echo 'movie id ' . htmlentities($id);
	});

	// will result in '/movies/id'
	$router->put('/(\d+)', function($id) {
		echo 'Update movie id ' . htmlentities($id);
	});

});

// Thunderbirds are go!
$router->run();

You can of course mount any callable you like:

class MoviesController {

	public function __construct($router) {

		// will result in '/movies'
		$router->get('/', function() {
			echo 'movies overview';
		});

		// will result in '/movies'
		$router->post('/', function() {
			echo 'add movie';
		});

		// will result in '/movies/id'
		$router->get('/(\d+)', function($id) {
			echo 'movie id ' . htmlentities($id);
		});

		// will result in '/movies/id'
		$router->put('/(\d+)', function($id) {
			echo 'Update movie id ' . htmlentities($id);
		});

	}

}

$router->mount('/movies', function() use ($router) { new MoviesController($router); });

Support for HEAD requests

bramus/router will now properly respond to HEAD requests, as per RFC2616 (Hypertext Transfer Protocol — HTTP/1.1) Specification:

The HEAD method is identical to GET except that the server MUST NOT return a message-body in the response. The metainformation contained in the HTTP headers in response to a HEAD request SHOULD be identical to the information sent in response to a GET request.

Internally the request method is overwritten to GET when a HEAD request is made. Output buffering then keeps output from trickling into the response.

Support for X-HTTP-Method-Override

It’s now also possible to use an X-HTTP-Method-Override header to override the HTTP Request Method.

Some HTTP clients can only work with simple GET and POST requests, or sometimes firewalls can spoil all the fun. Although there aren’t any hard standards here, the popular convention is to do a POST request and accept a request header X-HTTP-Method-Override with a string value containing one of PUT, PATCH or DELETE to override the method

bramus/router (GitHub) →
bramus/router on Packagist →
bramus/router Travis CI build status →

bramus/router — A lightweight and simple object oriented PHP Router

For one of the courses I teach I was in need of a PHP Router. Having explored the available routers out there I found they either were:

  • Outdated
  • Not object oriented
    (sorry Klein (which has been updated by now, but wasn’t at the time))
  • Rather bad at the separation of concerns
    (sorry Ham & Klein; a router should only route, not handle templates/logging/sessions/…)
  • Not powerful enough
    (sorry JREAM/route; there’s more than just GET you know)
  • To be part of a bigger framework
    (sorry Silex and Slim)
  • Bloated for a one-time lab/to get things quickly up and running
    (sorry Symfony Routing)

In the end I decided to write one myself which I’ve polised for publication over the past few days. The result is bramus/router, a lightweight and simple object oriented PHP Router. A typical implementation of the class is this:

// Require composer autoloader
require __DIR__ . '/vendor/autoload.php';

// Create a Router
$router = new \Bramus\Router\Router();

// Custom 404 Handler
$router->set404(function() {
	header('HTTP/1.1 404 Not Found');
	echo '404, route not found!';
});

// Static route: / (homepage)
$router->get('/', function() {
	echo '<h1>bramus/router</h1><p>Try these routes:<p><ul><li>/hello/<em>name</em></li><li>/blog</li><li>/blog/<em>year</em></li><li>/blog/<em>year</em>/<em>month</em></li><li>/blog/<em>year</em>/<em>month</em>/<em>day</em></li></ul>';
});

// Dynamic route: /hello/name
$router->get('/hello/(\w+)', function($name) {
	echo 'Hello ' . htmlentities($name);
});

// Dynamic route with (successive) optional subpatterns: /blog(/year(/month(/day(/slug))))
$router->get('/blog(/\d{4}(/\d{2}(/\d{2}(/[a-z0-9_-]+)?)?)?)?', function($year = null, $month = null, $day = null, $slug = null) {
	if (!$year) { echo 'Blog overview'; return; }
	if (!$month) { echo 'Blog year overview (' . $year . ')'; return; }
	if (!$day) { echo 'Blog month overview (' . $year . '-' . $month . ')'; return; }
	if (!$slug) { echo 'Blog day overview (' . $year . '-' . $month . '-' . $day . ')'; return; }
	echo 'Blogpost ' . htmlentities($slug) . ' detail (' . $year . '-' . $month . '-' . $day . ')';
});

// Thunderbirds are go!
$router->run();

(Yes, you must get your PCRE mojo on in order to define dynamic routes)

bramus/router also supports before route middlewares, before router middlewares, and after router middleware. These features allow one to integrate bramus/router with their favorite library (logging, templating, …):

$router = new \Bramus\Router\Router();
$tpl = new \Acme\Template\Template();

$router->get('/', function() use ($tpl) {
    $tpl->load('home.tpl');
    $tpl->setdata(array(
        'name' => 'Bramus!'
    ));
});

$router->run(function() use ($tpl) {
    $tpl->display();
});

An extensive writeup of these features is available on GitHub.

A final note worth mentioning is that bramus/router is installable via Composer and is unit tested.

bramus/router (GitHub) →
bramus/router on Packagist →
bramus/router Travis CI build status →