PHPackages                             ongom/router - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Framework](/categories/framework)
4. /
5. ongom/router

ActiveLibrary[Framework](/categories/framework)

ongom/router
============

A PHP library for routing

v1.2.1(2mo ago)110MITPHP

Since Nov 12Pushed 2mo ago1 watchersCompare

[ Source](https://github.com/felixongom/router)[ Packagist](https://packagist.org/packages/ongom/router)[ RSS](/packages/ongom-router/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (3)Dependencies (2)Versions (4)Used By (0)

ongom/router
============

[](#ongomrouter)

A lightweight and simple object oriented PHP Router.It users bramus/router in the background and the documentations are slightly similar. Here we are using static methods.

Features
--------

[](#features)

- Supports `GET`, `POST`, `PUT`, `DELETE`, `OPTIONS`, `PATCH` and `HEAD` request methods
- [Routing shorthands such as `get()`, `post()`, `put()`, …](#routing-shorthands)
- [Static Route Patterns](#route-patterns)
- Dynamic Route Patterns: [Dynamic PCRE-based Route Patterns](#dynamic-pcre-based-route-patterns) or [Dynamic Placeholder-based Route Patterns](#dynamic-placeholder-based-route-patterns)
- [Optional Route Subpatterns](#optional-route-subpatterns)
- [Supports `X-HTTP-Method-Override` header](#overriding-the-request-method)
- [Subrouting / Mounting Routes](#subrouting--mounting-routes)
- [Allowance of `Class@Method` calls](#classmethod-calls)
- [Custom 404 handling](#custom-404)
- [Before Route Middlewares](#before-route-middlewares)
- [Before Router Middlewares / Before App Middlewares](#before-router-middlewares)
- [After Router Middleware / After App Middleware (Finish Callback)](#after-router-middleware--run-callback)
- [Works fine in subfolders](#subfolder-support)

Prerequisites/Requirements
--------------------------

[](#prerequisitesrequirements)

- PHP 5.3 or greater
- [URL Rewriting](https://gist.github.com/bramus/5332525)

Usage
-----

[](#usage)

```
use Ongom\Router\Route;
// Require composer autoloader
require __DIR__ . '/vendor/autoload.php';

Route::get('/home', function(){
    echo 'hello router';
});
// Define more routes
// ...

// Run it!
Route::run();
```

### Routing

[](#routing)

Hook **routes** (a combination of one or more HTTP methods and a pattern) using `Route::match(method(s), pattern, function)`:

```
Route::match('GET|POST', 'pattern', function() { … });
```

`ongom/router` supports `GET`, `POST`, `PUT`, `PATCH`, `DELETE`, `HEAD` *(see [note](#a-note-on-making-head-requests))*, and `OPTIONS` HTTP 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](http://php.net/manual/en/language.types.callable.php). Only the first route matched will be handled. When no matching route is found, a 404 handler will be executed.

### Routing Shorthands

[](#routing-shorthands)

Shorthands for single request methods are provided:

```
Route::get('pattern', function() { /* ... */ });
Route::post('pattern', function() { /* ... */ });
Route::put('pattern', function() { /* ... */ });
Route::delete('pattern', function() { /* ... */ });
Route::options('pattern', function() { /* ... */ });
Route::patch('pattern', function() { /* ... */ });
```

You can use this shorthand for a route that can be accessed using any method:

```
Route::all('pattern', function() { … });
```

Note: Routes must be hooked before `Route::run();` is being called.

Note: There is no shorthand for `match()` as `ongom/router` will internally re-route such requrests to their equivalent `GET` request, in order to comply with RFC2616 *(see [note](#a-note-on-making-head-requests))*.

### Route Patterns

[](#route-patterns)

Route 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 Patterns

[](#static-route-patterns)

A static route pattern is a regular string representing a URI. It will be compared directly against the `path` part of the current URL.

Examples:

- `/about`
- `/contact`

Usage Examples:

```
// This route handling function will only be executed when visiting http(s)://www.example.org/about
Route::get('/about', function() {
    echo 'About Page Contents';
});
```

#### Dynamic PCRE-based Route Patterns

[](#dynamic-pcre-based-route-patterns)

This 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](https://courses.cs.washington.edu/courses/cse154/15sp/cheat-sheets/php-regex-cheat-sheet.pdf) 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
Route::get('/hello/\w+', function($name) {
    echo 'Hello ' . htmlentities($name);
});

// Good
Route::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:

```
Route::get('/movies/(\d+)/photos/(\d+)', function($movieId, $photoId) {
    echo 'Movie #' . $movieId . ', photo #' . $photoId;
});
```

#### Dynamic Placeholder-based Route Patterns

[](#dynamic-placeholder-based-route-patterns)

This 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 (`.*`).

```
Route::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:

```
Route::get('/movies/{foo}/photos/{bar}', function($movieId, $photoId) {
    echo 'Movie #' . $movieId . ', photo #' . $photoId;
});
```

### Optional Route Subpatterns

[](#optional-route-subpatterns)

Route 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)`:

```
Route::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/foo` and 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)`:

```
Route::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](http://www.php.net/manual/en/regexp.reference.repetition.php) to require the correct amount of numbers in the URL:

```
Route::get('/blog(/\d{4}(/\d{2}(/\d{2}(/[a-z0-9_-]+)?)?)?)?', function($year = null, $month = null, $day = null, $slug = null) {
    // ...
});
```

### Subrouting / Mounting Routes

[](#subrouting--mounting-routes)

Use `Route::group($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 `$fn` onto `/movies` will prefix `/movies` onto all following routes.

```
Route::group('/movies', function(){

    // will result in '/movies/'
    Route::get('/', function() {
        echo 'movies overview';
    });

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

});
```

Nesting of subroutes is possible, just define a second `Route::group()` in the callable that's already contained within a preceding `Route::group()`.

### `Class@Method` calls

[](#classmethod-calls)

We can route to the class action like so:

```
Route::get('/(\d+)', '\App\Controllers\User@showProfile');
```

When a request matches the specified route URI, the `showProfile` method on the `User` class 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()`

```
Route::setNamespace('\App\Controllers');
Route::get('/users/(\d+)', 'User@showProfile');
Route::get('/cars/(\d+)', 'Car@showProfile');
```

### Custom 404

[](#custom-404)

The default 404 handler sets a 404 status code and exits. You can override this default 404 handler by using `Route::set404(callable);`

```
Route::set404(function() {
    header('HTTP/1.1 404 Not Found');
    // ... do something special here
});
```

You can also define multiple custom routes e.x. you want to define an `/api` route, you can print a custom 404 page:

```
Route::set404('/api(/.*)?', function() {
    header('HTTP/1.1 404 Not Found');
    header('Content-Type: application/json');

    $jsonArray = array();
    $jsonArray['status'] = "404";
    $jsonArray['status_text'] = "route not defined";

    echo json_encode($jsonArray);
});
```

Also supported are `Class@Method` callables:

```
Route::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 `Route::trigger404()`

```
Route::get('/([a-z0-9-]+)', function($id) {
    if (!Posts::exists($id)) {
        Route::trigger404();
        return;
    }

    // …
});
```

### Before Route Middlewares

[](#before-route-middlewares)

`ongom/router` supports **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.

```
Route::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 Middlewares

[](#before-router-middlewares)

Before 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.

```
Route::before('GET', '/.*', function() {
    // ... this will always be executed
});
```

### After Router Middleware / Run Callback

[](#after-router-middleware--run-callback)

Run 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 `Route::run()` function. The run callback is route independent.

```
Route::run(function() { … });
```

Note: If the route handling function has `exit()`ed the run callback won't be run.

### Overriding the request method

[](#overriding-the-request-method)

Use `X-HTTP-Method-Override` to override the HTTP Request Method. Only works when the original Request Method is `POST`. Allowed values for `X-HTTP-Method-Override` are `PUT`, `DELETE`, or `PATCH`.

### Subfolder support

[](#subfolder-support)

Out-of-the box `ongom/router` will run in any (sub)folder you place it into … no adjustments to your code are needed. You can freely move your *entry script* `index.php` around, 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.org` using `public_html/` as its document root, with this little *entry script* `index.php`:

```
Route::get('/', function() { echo 'Index'; });
Route::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`), `ongom/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`), `ongom/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 `Route::group(…)` in this case.

#### Disabling subfolder support

[](#disabling-subfolder-support)

In case you **don't** want `ongom/router` to automatically adapt itself to the folder its being placed in, it's possible to manually override the *basePath* by calling `setBasePath()`. 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
Route::setBasePath('/');

Route::get('/', function() { echo 'Index'; });
Route::get('/hello', function() { echo 'Hello!'; });

Route::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 to `https://www.example.org/` and `https://www.example.org/hello` *(given that your `.htaccess` file – placed at the document root level – rewrites requests to it)*

Integration with other libraries
--------------------------------

[](#integration-with-other-libraries)

Integrate other libraries with `ongom/router` by making good use of the `use` keyword to pass dependencies into the handling functions.

```
$tpl = new \Acme\Template\Template();

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

Route::run(function(){
    $tpl->display();
});
```

Given this structure it is still possible to manipulate the output from within the After Router Middleware

A note on working with PUT
--------------------------

[](#a-note-on-working-with-put)

There's no such thing as `$_PUT` in PHP. One must fake it:

```
Route::put('/movies/(\d+)', function($id) {

    // Fake $_PUT
    $_PUT  = array();
    parse_str(file_get_contents('php://input'), $_PUT);

    // ...

});
```

A note on making HEAD requests
------------------------------

[](#a-note-on-making-head-requests)

When making `HEAD` requests all output will be buffered to prevent any content trickling into the response body, as defined in [RFC2616 (Hypertext Transfer Protocol -- HTTP/1.1)](http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.4):

> 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, `ongom/router` but will internally re-route `HEAD` requests to their equivalent `GET` request and automatically suppress all output.

Unit Testing &amp; Code Coverage
--------------------------------

[](#unit-testing--code-coverage)

`ongom/router` ships with unit tests using [PHPUnit](https://github.com/sebastianbergmann/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.

###  Health Score

37

—

LowBetter than 83% of packages

Maintenance86

Actively maintained with recent releases

Popularity8

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity41

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~240 days

Total

3

Last Release

71d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/72742b6d920009945cf5556377e410baf5155a3fb1399f475300f19e9652a059?d=identicon)[ongom](/maintainers/ongom)

---

Top Contributors

[![felixongom](https://avatars.githubusercontent.com/u/84242768?v=4)](https://github.com/felixongom "felixongom (1 commits)")

### Embed Badge

![Health badge](/badges/ongom-router/health.svg)

```
[![Health](https://phpackages.com/badges/ongom-router/health.svg)](https://phpackages.com/packages/ongom-router)
```

###  Alternatives

[laravel/prompts

Add beautiful and user-friendly forms to your command-line applications.

712181.8M596](/packages/laravel-prompts)[laravel/pail

Easily delve into your Laravel application's log files directly from the command line.

91545.3M590](/packages/laravel-pail)[nette/bootstrap

🅱 Nette Bootstrap: the simple way to configure and bootstrap your Nette application.

68535.8M592](/packages/nette-bootstrap)[drupal/core-recommended

Locked core dependencies; require this project INSTEAD OF drupal/core.

6939.5M343](/packages/drupal-core-recommended)[defstudio/pest-plugin-laravel-expectations

A plugin to add laravel tailored expectations to Pest

98548.9k4](/packages/defstudio-pest-plugin-laravel-expectations)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
