PHPackages                             rancoud/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. [Testing &amp; Quality](/categories/testing)
4. /
5. rancoud/router

ActiveLibrary[Testing &amp; Quality](/categories/testing)

rancoud/router
==============

Router package

5.0.0(1y ago)013.7k↓100%11MITPHPPHP &gt;=8.4.0CI passing

Since Apr 29Pushed 1mo ago1 watchersCompare

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

READMEChangelog (10)Dependencies (3)Versions (33)Used By (1)

Router Package
==============

[](#router-package)

[![Packagist PHP Version Support](https://camo.githubusercontent.com/728548473dbf3640d33478ed2e86b0d54d33053a906d90d605213f2c68f14a95/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f72616e636f75642f726f75746572)](https://camo.githubusercontent.com/728548473dbf3640d33478ed2e86b0d54d33053a906d90d605213f2c68f14a95/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f72616e636f75642f726f75746572)[![Packagist Version](https://camo.githubusercontent.com/5ccf02ab261b4717625d15c48b628cab2db05ab320e308d87fd126629568f22c/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f72616e636f75642f726f75746572)](https://packagist.org/packages/rancoud/router)[![Packagist Downloads](https://camo.githubusercontent.com/cefe30ff1ebec88e8096a4ac96754612582b55b8127ca1c31ab056b1fa25f2b1/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f72616e636f75642f726f75746572)](https://packagist.org/packages/rancoud/router)[![Composer dependencies](https://camo.githubusercontent.com/e176e220268ba29b476d8db8874191c7519478a64fd9992bf9973015edcffcce/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f646570656e64656e636965732d312d627269676874677265656e)](https://github.com/rancoud/router/blob/master/composer.json)[![Test workflow](https://camo.githubusercontent.com/b6c5b787017dae536f43730a08c8d6fec164ecd36f5e630a56c359dcff9ea082/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f72616e636f75642f726f757465722f746573742e796d6c3f6272616e63683d6d6173746572)](https://github.com/rancoud/router/actions/workflows/test.yml)[![Codecov](https://camo.githubusercontent.com/f5b86bd8ba7c1e099f1fc2870d2a50e87f0dbff91c0cea77d56a922d0ac9424c/68747470733a2f2f696d672e736869656c64732e696f2f636f6465636f762f632f6769746875622f72616e636f75642f726f757465723f6c6f676f3d636f6465636f76)](https://codecov.io/gh/rancoud/router)

Router PSR7 and PSR15.

Installation
------------

[](#installation)

```
composer require rancoud/router
```

Dependencies
------------

[](#dependencies)

Http package:

How to use it?
--------------

[](#how-to-use-it)

### General Case

[](#general-case)

```
// Instantiation
$router = new Router();

// Add routes
$router->get('/posts', function ($request, $next) {
    return (new MessageFactory())->createResponse(200, null, [], 'ok');
});

// Find route
$found = $router->findRoute('GET', '/posts');

// You can use PSR-7 request for finding Route
$found = $router->findRouteRequest(new \Rancoud\Http\Message\ServerRequest('GET', '/posts'));

// Dispatch (response is a PSR7 object \Psr\Http\Message\Response)
$response = $router->dispatch($request);

// Display Response
$response->send();
```

### Routes shortcuts

[](#routes-shortcuts)

```
// Methods shortcuts
$router->get('/posts/{id}', function ($request, $next) {});
$router->post('/posts/{id}', function ($request, $next) {});
$router->put('/posts/{id}', function ($request, $next) {});
$router->patch('/posts/{id}', function ($request, $next) {});
$router->delete('/posts/{id}', function ($request, $next) {});
$router->options('/posts/{id}', function ($request, $next) {});

// Any methods
$router->any('/posts/{id}', function ($request, $next) {});

// CRUD method
$router->crud('/posts', function ($request, $next) {});
```

### Route Parameters

[](#route-parameters)

Use the pattern `{name}` for naming your parameters

```
$router->get('/posts/{id}', function ($request, $next) {});
```

### Constraints

[](#constraints)

Use regex syntax for your constraints

```
// inline for simple case
$router->get('/{id:\d+}', function ($request, $next) {});

// complex
$route = new Route('GET', '/{id}', function ($request, $next) {});
$route->setParametersConstraints(['id' => '\d+']);
```

You can setup a global constraint when you use the same regex multiple times

```
$router->setGlobalParametersConstraints(['lang' => 'en|fr']);

// {lang} will use the global constraints
$router->get('/article/{lang}', function ($request, $next) {});

// {lang} will use the local constraints define by the route
$router->get('/news/{lang}', function ($request, $next) {})->setParametersConstraints(['lang' => 'jp']);
```

You can use on each route an optional parameters.
The parameters `{page}` will be replace with the value `1` if it is not present

```
$route = new Route('GET', '/{id}/{page}', function ($request, $next) {});
$route->setOptionalsParameters(['page' => 1]);
```

### Middlewares

[](#middlewares)

```
// global middleware for router
$router->addGlobalMiddleware(function ($request, $next) {});

// middleware for only route
$route = new Route('GET', '/{id}', function ($request, $next) {});
$route->addMiddleware(function ($request, $next) {});

// for passing to next middleware
$router->addGlobalMiddleware(function ($request, $next) {
    $next($request);
});

// you can add an instance of Router as a middleware
$subRouter1 = new Router();
$subRouter1->any('/api/books/{id}', function ($req, $next){
    return (new MessageFactory())->createResponse(200, null, [], 'testRouterception books');
});

$subRouter2 = new Router();
$subRouter2->any('/api/peoples/{id}', function ($req, $next){
    return (new MessageFactory())->createResponse(200, null, [], 'testRouterception peoples');
});

$router->addGlobalMiddleware($subRouter1);
$router->addGlobalMiddleware($subRouter2);
```

#### Router in Route in Router

[](#router-in-route-in-router)

```
// you can add an instance of Router in a Route callback
$subRouter1 = new Router();
$subRouter1->any('/api/books/{id}', function ($req, $next){
    return (new MessageFactory())->createResponse(200, null, [], 'testRouterception books');
});

$subRouter2 = new Router();
$subRouter2->any('/api/peoples/{id}', function ($req, $next){
    return (new MessageFactory())->createResponse(200, null, [], 'testRouterception peoples');
});

$router->any('/api/books/{id}', $subRouter1);
$router->any('/api/peoples/{id}', $subRouter2);
```

#### Default 404

[](#default-404)

```
// you can set a default 404
$router->setDefault404( static function ($request, $next) {
    return (new \Rancoud\Http\Message\Factory\Factory())->createResponse(404, '')->withBody(Rancoud\Http\Message\Stream::create('404 content'));
});

// it will return false because no Route is matching
$found = $router->findRoute('GET', '/posts');

// response contains the default 404 callback
$response = $router->dispatch($request);

$response->send();
```

**WARNING with 404 and Router as Middleware**

```
// create new Router with default 404
$subRouter = new Router();
$subRouter->any('/posts/{id:\d+}', function ($req, $next){
   return (new MessageFactory())->createResponse(200, null, [], 'read 1 post');
});
$subRouter->setDefault404( static function ($request, $next) {
    return (new \Rancoud\Http\Message\Factory\Factory())->createResponse(404, '')->withBody(Rancoud\Http\Message\Stream::create('404 content from subRouter'));
});

// you can add a Router as middleware
$router->any('/posts/{id}', $subRouter);

// it will return true because Router middleware is matching on /posts/{id}
$found = $router->findRoute('GET', '/posts/incorrect');

// response contains the default 404 callback from $subRouter
$response = $router->dispatch($request);

$response->send();
```

If you use Router as middleware **AND** set default 404 then `findRouteRequest` and `findRoute` will return `true`.
When calling `dispatch` it will use the callback setted as default 404 by the Router middleware.

Router Methods
--------------

[](#router-methods)

### General Commands

[](#general-commands)

#### Add route

[](#add-route)

- addRoute(route: \\Rancoud\\Router\\Route): void

#### Add route shortcuts

[](#add-route-shortcuts)

- get(url: string, callback: string|\\Closure|\\Psr\\Http\\Server\\MiddlewareInterface|\\Rancoud\\Router\\Router): \\Rancoud\\Router\\Route
- post(url: string, callback: string|\\Closure|\\Psr\\Http\\Server\\MiddlewareInterface|\\Rancoud\\Router\\Router): \\Rancoud\\Router\\Route
- put(url: string, callback: string|\\Closure|\\Psr\\Http\\Server\\MiddlewareInterface|\\Rancoud\\Router\\Router): \\Rancoud\\Router\\Route
- patch(url: string, callback: string|\\Closure|\\Psr\\Http\\Server\\MiddlewareInterface|\\Rancoud\\Router\\Router): \\Rancoud\\Router\\Route
- delete(url: string, callback: string|\\Closure|\\Psr\\Http\\Server\\MiddlewareInterface|\\Rancoud\\Router\\Router): \\Rancoud\\Router\\Route
- options(url: string, callback: string|\\Closure|\\Psr\\Http\\Server\\MiddlewareInterface|\\Rancoud\\Router\\Router): \\Rancoud\\Router\\Route
- any(url: string, callback: string|\\Closure|\\Psr\\Http\\Server\\MiddlewareInterface|\\Rancoud\\Router\\Router): void

#### Add route for a CRUD system

[](#add-route-for-a-crud-system)

- crud(prefixPath: string, callback: string|\\Closure|\\Psr\\Http\\Server\\MiddlewareInterface|\\Rancoud\\Router\\Router): void

It will create all this routes:
GET $prefixPath
GET / POST $prefixPath . '/new'
GET / POST / DELETE $prefixPath . '/{id:\\d+}'

#### Setup Router and Routes with an array

[](#setup-router-and-routes-with-an-array)

- setupRouterAndRoutesWithConfigArray(config: array): void

In this example you can setup router's middlewares and routes with an array

```
$config = [
    'router' => [
        'middlewares' => [
            'global_callback1',
            'global_callback2',
            'global_callback3'
        ],
        'constraints' => [
            'lang' => 'en|fr'
        ],
        'host' => '{service}.domain.{tld}',
        'host_constraint' => [
            'service' => 'api|backoffice|www|m',
            'tld' => 'en|jp'
        ],
        'default_404' => 'callable_404'
    ],
    'routes' => [
        [
            'methods' => ['GET'],
            'url' => '/articles/{id}',
            'callback' => 'route_callback',
            'constraints' => ['id' => '\w+'],
            'middlewares' => ['route_middleware1', 'route_middleware2'],
            'name' => 'route1'
        ],
        [
            'methods' => ['POST'],
            'url' => '/form',
            'callback' => 'callback',
        ],
        [
            'methods' => ['POST'],
            'url' => '/api/form',
            'callback' => 'callback',
            'host' => 'api.domain.{tld}',
            'host_constraint' => [
                'tld' => 'en|jp'
            ]
        ],
        [
            'methods' => ['GET'],
            'url' => '/blog/{page}',
            'callback' => 'callback',
            'optionals_parameters' => [
                'page' => '1'
            ]
        ]
    ]
];

$router = new Router();
$router->setupRouterAndRoutesWithConfigArray($config);

// you can add a Router as a callback
$subRoute = new Router();
$subRoute->setupRouterAndRoutesWithConfigArray($config);
$router->any('/(.*)', $subRoute);
```

#### Get Routes

[](#get-routes)

- getRoutes(): \\Rancoud\\Router\\Route\[\]

#### Find route

[](#find-route)

- findRoute(method: string, url: string, \[host: string = null\]): bool
- findRouteRequest(request: \\Psr\\Http\\Message\\ServerRequestInterface): bool
- getRouteParameters(): array

#### Run the found route

[](#run-the-found-route)

- dispatch(request: \\Psr\\Http\\Message\\ServerRequestInterface): \\Psr\\Http\\Message\\Response
- handle(request: \\Psr\\Http\\Message\\ServerRequestInterface): \\Psr\\Http\\Message\\Response

The difference between dispatch and handle is dispatch is used in first place.
Handle is from the PSR17 in Psr\\Http\\Message\\ServerRequestInterface, it's useful for middleware.

#### Middlewares

[](#middlewares-1)

- addGlobalMiddleware(middleware: \\Closure|\\Psr\\Http\\Server\\MiddlewareInterface|\\Rancoud\\Router\\Router|string): void
- setGlobalMiddlewares(middlewares: array): void

#### Global constraints

[](#global-constraints)

- setGlobalParametersConstraints(constraints: array): void
- setGlobalHostConstraints(constraints: array): void

#### Generate url for a named route

[](#generate-url-for-a-named-route)

- generateUrl(routeName: string, \[routeParameters: array = \[\]\]): ?string

#### Host constraints

[](#host-constraints)

- setGlobalHost(host: string): void

#### Default 404

[](#default-404-1)

- setDefault404(callback: mixed): void

Route Constructor
-----------------

[](#route-constructor)

### Settings

[](#settings)

#### Mandatory

[](#mandatory)

ParameterTypeDescriptionmethodsstring | arraymethods matching with the routeurlstringurl to matchcallbackstring | Closure | \\Psr\\Http\\Server\\MiddlewareInterface | \\Rancoud\\Router\\Routercallback when route is calling by routerRoute Methods
-------------

[](#route-methods)

### General Commands

[](#general-commands-1)

#### Getters/Setters

[](#getterssetters)

- getMethods(): array
- getUrl(): string
- getName(): string
- setName(name: string): void

#### Constraints

[](#constraints-1)

- setParametersConstraints(constraints: array): void
- getParametersConstraints(): array
- compileRegex(globalConstraints: array): string
- setOptionalsParameters(optionalsParameters: array): void
- getOptionalsParameters(): array

#### Callback

[](#callback)

- getCallback(): mixed

#### Middlewares

[](#middlewares-2)

- addMiddleware(middleware: \\Closure|\\Psr\\Http\\Server\\MiddlewareInterface|\\Rancoud\\Router\\Router|string): array
- getMiddlewares(): array

#### Generate Url

[](#generate-url)

- generateUrl(\[routeParameters: array = \[\]\]): string

#### Host

[](#host)

- getHost(): ?string
- setHost(host: string, \[hostConstraints: array = \[\]\]): void
- setHostConstraints(constraints: array): void
- isSameHost(host: string, globalConstraints: array = \[\]): bool
- getHostParameters(): array

How to Dev
----------

[](#how-to-dev)

`composer ci` for php-cs-fixer and phpunit and coverage
`composer lint` for php-cs-fixer
`composer test` for phpunit and coverage

###  Health Score

55

—

FairBetter than 98% of packages

Maintenance71

Regular maintenance activity

Popularity25

Limited adoption so far

Community12

Small or concentrated contributor base

Maturity92

Battle-tested with a long release history

 Bus Factor1

Top contributor holds 73.4% 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 ~88 days

Recently: every ~40 days

Total

30

Last Release

383d ago

Major Versions

1.0.8 → 2.0.02020-07-10

2.0.1 → 3.0.02020-07-22

3.2.0 → 4.0.02024-12-07

4.0.1 → 5.0.02025-04-21

PHP version history (3 changes)1.0.0PHP &gt;=7.2.0

2.0.0PHP &gt;=7.4.0

5.0.0PHP &gt;=8.4.0

### Community

Maintainers

![](https://www.gravatar.com/avatar/829a536bd4f71cadcd0266e272ccaf413e3fc9f2937248c9a2317ef0bf2d25ee?d=identicon)[rancoud](/maintainers/rancoud)

---

Top Contributors

[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (245 commits)")[![rancoud](https://avatars.githubusercontent.com/u/1884186?v=4)](https://github.com/rancoud "rancoud (89 commits)")

---

Tags

composercoveragehttppackagistphpphp7php8phpunitpsr-15psr-7router

###  Code Quality

TestsPHPUnit

Code StylePHP CS Fixer

### Embed Badge

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

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

###  Alternatives

[phpspec/prophecy

Highly opinionated mocking framework for PHP 5.3+

8.5k551.7M678](/packages/phpspec-prophecy)[vimeo/psalm

A static analysis tool for finding errors in PHP applications

5.8k77.5M6.7k](/packages/vimeo-psalm)[brianium/paratest

Parallel testing for PHP

2.5k118.8M753](/packages/brianium-paratest)[beberlei/assert

Thin assertion library for input validation in business models.

2.4k96.9M571](/packages/beberlei-assert)[mikey179/vfsstream

Virtual file system to mock the real file system in unit tests.

1.4k108.0M2.7k](/packages/mikey179-vfsstream)[orchestra/testbench

Laravel Testing Helper for Packages Development

2.2k39.1M32.0k](/packages/orchestra-testbench)

PHPackages © 2026

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