|  Download bramus/router        
 A lightweight and simple object oriented PHP Router.
Built by Bram(us) Van Damme _(https://www.bram.us)_ and Contributors FeaturesPrerequisites/RequirementsInstallationInstallation is possible using Composer composer require bramus/router ~1.5
 DemoA demo is included in the demosubfolder. Serve it using your favorite web server, or using PHP 5.4+'s built-in server by executingphp -S localhost:8080on the shell. A.htaccessfor use with Apache is included. Additionally a demo of a mutilingual router is also included. This can be found in the demo-multilangsubfolder and can be ran in the same manner as the normal demo. UsageCreate an instance of \Bramus\Router\Router, define some routes onto it, and run it. // Require composer autoloader
require __DIR__ . '/vendor/autoload.php';
// Create Router instance
$router = new \Bramus\Router\Router();
// Define routes
// ...
// Run it!
$router->run();
 RoutingHook __routes__ (a combination of one or more HTTP methods and a pattern) using $router->match(method(s), pattern, function): $router->match('GET|POST', 'pattern', function() { ? });
 bramus/routersupportsGET,POST,PUT,PATCH,DELETE,HEAD_(see note)_, andOPTIONSHTTP request methods. Pass in a single request method, or multiple request methods separated by|.
 When a route matches against the current URL (e.g. $_SERVER['REQUEST_URI']), the attached __route handling function__ will be executed. The route handling function must be a callable. Only the first route matched will be handled. When no matching route is found, a 404 handler will be executed. Routing ShorthandsShorthands for single request methods are provided: $router->get('pattern', function() { /.../ });
$router->post('pattern', function() { /.../ });
$router->put('pattern', function() { /.../ });
$router->delete('pattern', function() { /.../ });
$router->options('pattern', function() { /.../ });
$router->patch('pattern', function() { /.../ });
 You can use this shorthand for a route that can be accessed using any method: $router->all('pattern', function() { ? });
 Note: Routes must be hooked before $router->run();is being called. Note: There is no shorthand for match()asbramus/routerwill internally re-route such requrests to their equivalentGETrequest, in order to comply with RFC2616 _(see note)_. Route PatternsRoute Patterns can be static or dynamic: 
__Static Route Patterns__ contain no dynamic parts and must match exactly against the `path` part of the current URL.
__Dynamic Route Patterns__ contain dynamic parts that can vary per request. The varying parts are named __subpatterns__ and are defined using either Perl-compatible regular expressions (PCRE) or by using __placeholders__
 Static Route PatternsA static route pattern is a regular string representing a URI. It will be compared directly against the pathpart of the current URL. Examples: Usage Examples: // This route handling function will only be executed when visiting http(s)://www.example.org/about
$router->get('/about', function() {
    echo 'About Page Contents';
});
 Dynamic PCRE-based Route PatternsThis type of Route Patterns contain dynamic parts which can vary per request. The varying parts are named __subpatterns__ and are defined using regular expressions. Examples: 
`/movies/(\d+)`
`/profile/(\w+)`
 Commonly used PCRE-based subpatterns within Dynamic Route Patterns are: 
`\d+` = One or more digits (0-9)
`\w+` = One or more word characters (a-z 0-9 _)
`[a-z0-9_-]+` = One or more word characters (a-z 0-9 _) and the dash (-)
`.*` = Any character (including `/`), zero or more
`[^/]+` = Any character but `/`, one or more
 Note: The PHP PCRE Cheat Sheet might come in handy. The __subpatterns__ defined in Dynamic PCRE-based Route Patterns are converted to parameters which are passed into the route handling function. Prerequisite is that these subpatterns need to be defined as __parenthesized subpatterns__, which means that they should be wrapped between parens: // Bad
$router->get('/hello/\w+', function($name) {
    echo 'Hello ' . htmlentities($name);
});
// Good
$router->get('/hello/(\w+)', function($name) {
    echo 'Hello ' . htmlentities($name);
});
 Note: The leading /at the very beginning of a route pattern is not mandatory, but is recommended. When multiple subpatterns are defined, the resulting __route handling parameters__ are passed into the route handling function in the order they are defined in: $router->get('/movies/(\d+)/photos/(\d+)', function($movieId, $photoId) {
    echo 'Movie #' . $movieId . ', photo #' . $photoId;
});
 Dynamic Placeholder-based Route PatternsThis type of Route Patterns are the same as __Dynamic PCRE-based Route Patterns__, but with one difference: they don't use regexes to do the pattern matching but they use the more easy __placeholders__ instead. Placeholders are strings surrounded by curly braces, e.g. {name}. You don't need to add parens around placeholders. Examples: 
`/movies/{id}`
`/profile/{username}`
 Placeholders are easier to use than PRCEs, but offer you less control as they internally get translated to a PRCE that matches any character (.*). $router->get('/movies/{movieId}/photos/{photoId}', function($movieId, $photoId) {
    echo 'Movie #' . $movieId . ', photo #' . $photoId;
});
 Note: the name of the placeholder does not need to match with the name of the parameter that is passed into the route handling function: $router->get('/movies/{foo}/photos/{bar}', function($movieId, $photoId) {
    echo 'Movie #' . $movieId . ', photo #' . $photoId;
});
 Optional Route SubpatternsRoute subpatterns can be made optional by making the subpatterns optional by adding a ?after them. Think of blog URLs in the form of/blog(/year)(/month)(/day)(/slug): $router->get(
    '/blog(/\d+)?(/\d+)?(/\d+)?(/[a-z0-9_-]+)?',
    function($year = null, $month = null, $day = null, $slug = null) {
        if (!$year) { echo 'Blog overview'; return; }
        if (!$month) { echo 'Blog year overview'; return; }
        if (!$day) { echo 'Blog month overview'; return; }
        if (!$slug) { echo 'Blog day overview'; return; }
        echo 'Blogpost ' . htmlentities($slug) . ' detail';
    }
);
 The code snippet above responds to the URLs /blog,/blog/year,/blog/year/month,/blog/year/month/day, and/blog/year/month/day/slug. Note: With optional parameters it is important that the leading /of the subpatterns is put inside the subpattern itself. Don't forget to set default values for the optional parameters. The code snipped above unfortunately also responds to URLs like /blog/fooand states that the overview needs to be shown - which is incorrect. Optional subpatterns can be made successive by extending the parenthesized subpatterns so that they contain the other optional subpatterns: The pattern should resemble/blog(/year(/month(/day(/slug))))instead of the previous/blog(/year)(/month)(/day)(/slug): $router->get('/blog(/\d+(/\d+(/\d+(/[a-z0-9_-]+)?)?)?)?', function($year = null, $month = null, $day = null, $slug = null) {
    // ...
});
 Note: It is highly recommended to __always__ define successive optional parameters. To make things complete use quantifiers to require the correct amount of numbers in the URL: $router->get('/blog(/\d{4}(/\d{2}(/\d{2}(/[a-z0-9_-]+)?)?)?)?', function($year = null, $month = null, $day = null, $slug = null) {
    // ...
});
 Subrouting / Mounting RoutesUse $router->mount($baseroute, $fn)to mount a collection of routes onto a subroute pattern. The subroute pattern is prefixed onto all following routes defined in the scope. e.g. Mounting a callback$fnonto/movieswill prefix/moviesonto all following routes. $router->mount('/movies', function() use ($router) {
    // will result in '/movies/'
    $router->get('/', function() {
        echo 'movies overview';
    });
    // will result in '/movies/id'
    $router->get('/(\d+)', function($id) {
        echo 'movie id ' . htmlentities($id);
    });
});
 Nesting of subroutes is possible, just define a second $router->mount()in the callable that's already contained within a preceding$router->mount(). Class@Methodcalls
We can route to the class action like so: $router->get('/(\d+)', '\App\Controllers\User@showProfile');
 When a request matches the specified route URI, the showProfilemethod on theUserclass will be executed. The defined route parameters will be passed to the class method. The method can be static (recommended) or non-static (not-recommended). In case of a non-static method, a new instance of the class will be created. If most/all of your handling classes are in one and the same namespace, you can set the default namespace to use on your router instance via setNamespace() $router->setNamespace('\App\Controllers');
$router->get('/users/(\d+)', 'User@showProfile');
$router->get('/cars/(\d+)', 'Car@showProfile');
 Custom 404The default 404 handler sets a 404 status code and exits. You can override this default 404 handler by using $router->set404(callable); $router->set404(function() {
    header('HTTP/1.1 404 Not Found');
    // ... do something special here
});
 Also supported are Class@Methodcallables: $router->set404('\App\Controllers\Error@notFound');
 The 404 handler will be executed when no route pattern was matched to the current URL. ? You can also manually trigger the 404 handler by calling $router->trigger404() $router->get('/([a-z0-9-]+)', function($id) use ($router) {
    if (!Posts::exists($id)) {
        $router->trigger404();
        return;
    }
    // ?
});
 Before Route Middlewaresbramus/routersupports __Before Route Middlewares__, which are executed before the route handling is processed.
 Like route handling functions, you hook a handling function to a combination of one or more HTTP request methods and a specific route pattern. $router->before('GET|POST', '/admin/.*', function() {
    if (!isset($_SESSION['user'])) {
        header('location: /auth/login');
        exit();
    }
});
 Unlike route handling functions, more than one before route middleware is executed when more than one route match is found. Before Router MiddlewaresBefore route middlewares are route specific. Using a general route pattern (viz. _all URLs_), they can become __Before Router Middlewares__ _(in other projects sometimes referred to as before app middlewares)_ which are always executed, no matter what the requested URL is. $router->before('GET', '/.*', function() {
    // ... this will always be executed
});
 After Router Middleware / Run CallbackRun one (1) middleware function, name the __After Router Middleware__ _(in other projects sometimes referred to as after app middlewares)_ after the routing was processed. Just pass it along the $router->run()function. The run callback is route independent. $router->run(function() { ? });
 Note: If the route handling function has exit()ed the run callback won't be run. Overriding the request methodUse X-HTTP-Method-Overrideto override the HTTP Request Method. Only works when the original Request Method isPOST. Allowed values forX-HTTP-Method-OverridearePUT,DELETE, orPATCH. Subfolder supportOut-of-the box bramus/routerwill run in any (sub)folder you place it into ? no adjustments to your code are needed. You can freely move your _entry script_index.phparound, and the router will automatically adapt itself to work relatively from the current folder's path by mounting all routes onto that __basePath__. Say you have a server hosting the domain www.example.orgusingpublic_html/as its document root, with this little _entry script_index.php: $router->get('/', function() { echo 'Index'; });
$router->get('/hello', function() { echo 'Hello!'; });
 
If your were to place this file _(along with its accompanying `.htaccess` file or the like)_ at the document root level (e.g. `public_html/index.php`), `bramus/router` will mount all routes onto the domain root (e.g. `/`) and thus respond to `https://www.example.org/` and `https://www.example.org/hello`.
If you were to move this file _(along with its accompanying `.htaccess` file or the like)_ into a subfolder (e.g. `public_html/demo/index.php`), `bramus/router` will mount all routes onto the current path (e.g. `/demo`) and thus repsond to `https://www.example.org/demo` and `https://www.example.org/demo/hello`. There's no need for `$router->mount(?)` in this case.
 Disabling subfolder supportIn case you don't want bramus/routerto automatically adapt itself to the folder its being placed in, it's possible to manually override the _basePath_ by callingsetBasePath(). This is necessary in the _(uncommon)_ situation where your _entry script_ and your _entry URLs_ are not tightly coupled _(e.g. when the entry script is placed into a subfolder that does not need be part of the URLs it responds to)_. // Override auto base path detection
$router->setBasePath('/');
$router->get('/', function() { echo 'Index'; });
$router->get('/hello', function() { echo 'Hello!'; });
$router->run();
 If you were to place this file into a subfolder (e.g. public_html/some/sub/folder/index.php), it will still mount the routes onto the domain root (e.g./) and thus respond tohttps://www.example.org/andhttps://www.example.org/hello_(given that your.htaccessfile ? placed at the document root level ? rewrites requests to it)_ Integration with other librariesIntegrate other libraries with bramus/routerby making good use of theusekeyword to pass dependencies into the handling functions. $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();
});
 Given this structure it is still possible to manipulate the output from within the After Router Middleware A note on working with PUTThere's no such thing as $_PUTin PHP. One must fake it: $router->put('/movies/(\d+)', function($id) {
    // Fake $_PUT
    $_PUT  = array();
    parse_str(file_get_contents('php://input'), $_PUT);
    // ...
});
 A note on making HEAD requestsWhen making HEADrequests all output will be buffered to prevent any content trickling into the response body, as defined in RFC2616 (Hypertext Transfer Protocol -- HTTP/1.1): > 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. This method can be used for obtaining metainformation about the entity implied by the request without transferring the entity-body itself. This method is often used for testing hypertext links for validity, accessibility, and recent modification. To achieve this, bramus/routerbut will internally re-routeHEADrequests to their equivalentGETrequest and automatically suppress all output. Unit Testing & Code Coveragebramus/routerships with unit tests using PHPUnit.
 
If PHPUnit is installed globally run `phpunit` to run the tests.
If PHPUnit is not installed globally, install it locally throuh composer by running `composer install --dev`. Run the tests themselves by calling `vendor/bin/phpunit`.
 The included `composer.json` will also install `php-code-coverage` which allows one to generate a __Code Coverage Report__. Run `phpunit --coverage-html ./tests-report` (XDebug required), a report will be placed into the `tests-report` subfolder.
 Acknowledgementsbramus/routeris inspired upon Klein, Ham, and JREAM/route . Whilst Klein provides lots of features it is not object oriented. Whilst Ham is Object Oriented, it's bad at _separation of concerns_ as it also provides templating within the routing class. Whilst JREAM/route is a good starting point it is limited in what it does (only GET routes for example).
 Licensebramus/routeris released under the MIT public license. See the enclosedLICENSEfor details.
 |