README.md

Aura Router

Aura Router is a PHP package that implements web routing. Given a URI path and a copy of $_SERVER, it will extract controller, action, and parameter values for a specific application route.

Your application foundation or framework is expected to take the information provided by the matching route and dispatch to a controller on its own. As long as your system can provide a URI path string and a representative copy of $_SERVER, you can use Aura Router.

You will need to place the Map object where you can get to it from your application; e.g., in a registry, a service locator, or a dependency injection container. Describing such placement is beyond the scope of this document.

Matching A Route

To match a URI path against your route map, call match() with a path string and the $_SERVER values.

<?php
// get the incoming request URI path
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
// get the route based on the path and server
$route = $map->match($path, $_SERVER);

The match() method does not parse the URI or use $_SERVER internally. This is becuase different systems may have different ways of representing that information; e.g., through a URI object or a context object. As long as you can pass the string path and a server array, you can use Aura Router in your application foundation or framework.

The returned $route object will contain, among other things, a $values array with values for each of the parameters identified by the route path. For example, matching a route with the path /{:controller}/{:action}/{:id} will populate the $route->values array with controller, action, and id keys.

Dispatching A Route

Now that you have route, you can dispatch it. The following is what a foundation or framework system might do with a route to invoke a page controller.

Aura Router does not do dynamic matching of routes; a route must have a name to be able to generate a path from it.

The example shows that passing an array of data as the second parameter will cause that data to be interpolated into the route path. This data array is optional. If there are path params without matching data keys, those params will not be replaced, leaving the {:param} token in the path. If there are data keys without matching params, those values will not be added to the path.

Advanced Usage

Complex Route Specification

When you add a complex route specification, you describe extra information related to the path as an array with one or more of the following recognized keys:

method -- The $server['REQUEST_METHOD'] must match one of these values.

secure -- When true the $server['HTTPS'] value must be on, or the request must be on port 443; when false, neither of those must be in place.

routable -- When false the route will not be used for matching, only for generating paths.

is_match -- A custom callback or closure with the signature function(array $server, \ArrayObject $matches) that returns true on a match, or false if not. This allows developers to build any kind of matching logic for the route, and to change the $matches for param values from the path.

generate -- A custom callback or closure with the signature function(\aura\router\Route $route, array $data) that returns a modified $data array to be used when generating the path.

Note that using closures, instead of callbacks, means you will not be able to serialize() or var_export() the router map for caching.

Simple Routes

You don't need to specify a complex route specification. If you pass a string for the route instead of an array ...

<?php
$map->add('archive', '/archive/{:year}/{:month}/{:day}');

... then Aura Router will use a default subpattern that matches everything except slashes for the path params, and use the route name as the default value for 'action'. Thus, the above short-form route is equivalent to the following long-form route:

Attaching Route Groups

You can add a series of routes all at once under a single "mount point" in your application. For example, if you want all your blog-related routes to be mounted at '/blog' in your application, you can do this:

Constructor-Time Attachment

You can configure your routes in a single array of attachment groups, and then pass them to the Map constructor all at once. This allows you to separate configuration and construction of routes.

Note that you can specify a name_prefix as part of the common route information for each attached route group; the route names in that group will be prefixed with that value. This helps with deconfliction of routes with the same names in different groups.

This technique can be very effective with modular application packages. Each package can return an array for its own route group specification, and a system-specific configuration mechanism can collect each spec into a common array for the Map. For example:

Caching

You may wish to cache the route map for production deployments so that the Map does not have to build the route objects from definitions on each page load. The methods getRoutes() and setRoutes() may be used for that purpose.

The following is a naive example for file-based caching and restoring of Map routes:

Note that if there are closures in the route definitions, you will not be able to cache the Map routes; this is because closures cannot be represented properly for caching. Use traditional callbacks instead of closures if you wish to pursue a cache strategy.