{"id":15029809,"url":"https://github.com/rancoud/router","last_synced_at":"2026-03-01T01:34:01.930Z","repository":{"id":37579844,"uuid":"124849461","full_name":"rancoud/Router","owner":"rancoud","description":"Router Package","archived":false,"fork":false,"pushed_at":"2025-04-01T12:20:13.000Z","size":570,"stargazers_count":0,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-04T00:34:34.745Z","etag":null,"topics":["composer","coverage","http","packagist","php","php74","php8","php80","php81","phpunit","phpunit9","psr-15","psr-7","router"],"latest_commit_sha":null,"homepage":"https://packagist.org/packages/rancoud/router","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rancoud.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-03-12T07:21:41.000Z","updated_at":"2025-04-01T12:20:16.000Z","dependencies_parsed_at":"2024-01-04T11:32:13.892Z","dependency_job_id":"f30eb717-63d5-46ec-b0c4-8ff9025d655c","html_url":"https://github.com/rancoud/Router","commit_stats":{"total_commits":142,"total_committers":3,"mean_commits":"47.333333333333336","dds":"0.43661971830985913","last_synced_commit":"b95d441a325b0cef12bec905ea871f9b34fd38d5"},"previous_names":[],"tags_count":29,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rancoud%2FRouter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rancoud%2FRouter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rancoud%2FRouter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rancoud%2FRouter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rancoud","download_url":"https://codeload.github.com/rancoud/Router/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248109619,"owners_count":21049345,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["composer","coverage","http","packagist","php","php74","php8","php80","php81","phpunit","phpunit9","psr-15","psr-7","router"],"created_at":"2024-09-24T20:11:40.607Z","updated_at":"2026-03-01T01:34:01.885Z","avatar_url":"https://github.com/rancoud.png","language":"PHP","readme":"# Router Package\n\n![Packagist PHP Version Support](https://img.shields.io/packagist/php-v/rancoud/router)\n[![Packagist Version](https://img.shields.io/packagist/v/rancoud/router)](https://packagist.org/packages/rancoud/router)\n[![Packagist Downloads](https://img.shields.io/packagist/dt/rancoud/router)](https://packagist.org/packages/rancoud/router)\n[![Composer dependencies](https://img.shields.io/badge/dependencies-1-brightgreen)](https://github.com/rancoud/router/blob/master/composer.json)\n[![Test workflow](https://img.shields.io/github/actions/workflow/status/rancoud/router/test.yml?branch=master)](https://github.com/rancoud/router/actions/workflows/test.yml)\n[![Codecov](https://img.shields.io/codecov/c/github/rancoud/router?logo=codecov)](https://codecov.io/gh/rancoud/router)\n\nRouter PSR7 and PSR15.  \n\n## Installation\n```php\ncomposer require rancoud/router\n```\n\n## Dependencies\nHttp package: [https://github.com/rancoud/Http](https://github.com/rancoud/Http)\n\n## How to use it?\n### General Case\n```php\n// Instantiation\n$router = new Router();\n\n// Add routes\n$router-\u003eget('/posts', function ($request, $next) {\n    return (new MessageFactory())-\u003ecreateResponse(200, null, [], 'ok');\n});\n\n// Find route\n$found = $router-\u003efindRoute('GET', '/posts');\n\n// You can use PSR-7 request for finding Route\n$found = $router-\u003efindRouteRequest(new \\Rancoud\\Http\\Message\\ServerRequest('GET', '/posts'));\n\n// Dispatch (response is a PSR7 object \\Psr\\Http\\Message\\Response)\n$response = $router-\u003edispatch($request);\n\n// Display Response\n$response-\u003esend();\n```\n\n### Routes shortcuts\n```php\n// Methods shortcuts\n$router-\u003eget('/posts/{id}', function ($request, $next) {});\n$router-\u003epost('/posts/{id}', function ($request, $next) {});\n$router-\u003eput('/posts/{id}', function ($request, $next) {});\n$router-\u003epatch('/posts/{id}', function ($request, $next) {});\n$router-\u003edelete('/posts/{id}', function ($request, $next) {});\n$router-\u003eoptions('/posts/{id}', function ($request, $next) {});\n\n// Any methods\n$router-\u003eany('/posts/{id}', function ($request, $next) {});\n\n// CRUD method\n$router-\u003ecrud('/posts', function ($request, $next) {});\n```\n### Route Parameters\nUse the pattern `{name}` for naming your parameters  \n```php\n$router-\u003eget('/posts/{id}', function ($request, $next) {});\n```\n\n### Constraints\nUse regex syntax for your constraints\n```php\n// inline for simple case\n$router-\u003eget('/{id:\\d+}', function ($request, $next) {});\n\n// complex\n$route = new Route('GET', '/{id}', function ($request, $next) {});\n$route-\u003esetParametersConstraints(['id' =\u003e '\\d+']);\n```\n\nYou can setup a global constraint when you use the same regex multiple times  \n```php\n$router-\u003esetGlobalParametersConstraints(['lang' =\u003e 'en|fr']);\n\n// {lang} will use the global constraints\n$router-\u003eget('/article/{lang}', function ($request, $next) {});\n\n// {lang} will use the local constraints define by the route\n$router-\u003eget('/news/{lang}', function ($request, $next) {})-\u003esetParametersConstraints(['lang' =\u003e 'jp']);\n```\n\nYou can use on each route an optional parameters.  \nThe parameters `{page}` will be replace with the value `1` if it is not present  \n```php\n$route = new Route('GET', '/{id}/{page}', function ($request, $next) {});\n$route-\u003esetOptionalsParameters(['page' =\u003e 1]);\n```\n\n### Middlewares\n```php\n// global middleware for router\n$router-\u003eaddGlobalMiddleware(function ($request, $next) {});\n\n// middleware for only route\n$route = new Route('GET', '/{id}', function ($request, $next) {});\n$route-\u003eaddMiddleware(function ($request, $next) {});\n\n// for passing to next middleware\n$router-\u003eaddGlobalMiddleware(function ($request, $next) {\n    $next($request);\n});\n\n// you can add an instance of Router as a middleware\n$subRouter1 = new Router();\n$subRouter1-\u003eany('/api/books/{id}', function ($req, $next){\n    return (new MessageFactory())-\u003ecreateResponse(200, null, [], 'testRouterception books');\n});\n\n$subRouter2 = new Router();\n$subRouter2-\u003eany('/api/peoples/{id}', function ($req, $next){\n    return (new MessageFactory())-\u003ecreateResponse(200, null, [], 'testRouterception peoples');\n});\n\n$router-\u003eaddGlobalMiddleware($subRouter1);\n$router-\u003eaddGlobalMiddleware($subRouter2);\n```\n\n#### Router in Route in Router\n```php\n// you can add an instance of Router in a Route callback\n$subRouter1 = new Router();\n$subRouter1-\u003eany('/api/books/{id}', function ($req, $next){\n    return (new MessageFactory())-\u003ecreateResponse(200, null, [], 'testRouterception books');\n});\n\n$subRouter2 = new Router();\n$subRouter2-\u003eany('/api/peoples/{id}', function ($req, $next){\n    return (new MessageFactory())-\u003ecreateResponse(200, null, [], 'testRouterception peoples');\n});\n\n$router-\u003eany('/api/books/{id}', $subRouter1);\n$router-\u003eany('/api/peoples/{id}', $subRouter2);\n```\n\n#### Default 404\n```php\n// you can set a default 404\n$router-\u003esetDefault404( static function ($request, $next) {\n    return (new \\Rancoud\\Http\\Message\\Factory\\Factory())-\u003ecreateResponse(404, '')-\u003ewithBody(Rancoud\\Http\\Message\\Stream::create('404 content'));\n});\n\n// it will return false because no Route is matching\n$found = $router-\u003efindRoute('GET', '/posts');\n\n// response contains the default 404 callback\n$response = $router-\u003edispatch($request);\n\n$response-\u003esend();\n```\n**WARNING with 404 and Router as Middleware**  \n```php\n// create new Router with default 404\n$subRouter = new Router();\n$subRouter-\u003eany('/posts/{id:\\d+}', function ($req, $next){\n   return (new MessageFactory())-\u003ecreateResponse(200, null, [], 'read 1 post');\n});\n$subRouter-\u003esetDefault404( static function ($request, $next) {\n    return (new \\Rancoud\\Http\\Message\\Factory\\Factory())-\u003ecreateResponse(404, '')-\u003ewithBody(Rancoud\\Http\\Message\\Stream::create('404 content from subRouter'));\n});\n\n// you can add a Router as middleware \n$router-\u003eany('/posts/{id}', $subRouter);\n\n// it will return true because Router middleware is matching on /posts/{id}\n$found = $router-\u003efindRoute('GET', '/posts/incorrect');\n\n// response contains the default 404 callback from $subRouter\n$response = $router-\u003edispatch($request);\n\n$response-\u003esend();\n```\nIf you use Router as middleware **AND** set default 404 then `findRouteRequest` and `findRoute` will return `true`.  \nWhen calling `dispatch` it will use the callback setted as default 404 by the Router middleware.    \n\n## Router Methods\n### General Commands  \n#### Add route\n* addRoute(route: \\Rancoud\\Router\\Route): void  \n\n#### Add route shortcuts\n* get(url: string, callback: string|\\Closure|\\Psr\\Http\\Server\\MiddlewareInterface|\\Rancoud\\Router\\Router): \\Rancoud\\Router\\Route  \n* post(url: string, callback: string|\\Closure|\\Psr\\Http\\Server\\MiddlewareInterface|\\Rancoud\\Router\\Router): \\Rancoud\\Router\\Route  \n* put(url: string, callback: string|\\Closure|\\Psr\\Http\\Server\\MiddlewareInterface|\\Rancoud\\Router\\Router): \\Rancoud\\Router\\Route  \n* patch(url: string, callback: string|\\Closure|\\Psr\\Http\\Server\\MiddlewareInterface|\\Rancoud\\Router\\Router): \\Rancoud\\Router\\Route  \n* delete(url: string, callback: string|\\Closure|\\Psr\\Http\\Server\\MiddlewareInterface|\\Rancoud\\Router\\Router): \\Rancoud\\Router\\Route  \n* options(url: string, callback: string|\\Closure|\\Psr\\Http\\Server\\MiddlewareInterface|\\Rancoud\\Router\\Router): \\Rancoud\\Router\\Route  \n* any(url: string, callback: string|\\Closure|\\Psr\\Http\\Server\\MiddlewareInterface|\\Rancoud\\Router\\Router): void  \n\n#### Add route for a CRUD system\n* crud(prefixPath: string, callback: string|\\Closure|\\Psr\\Http\\Server\\MiddlewareInterface|\\Rancoud\\Router\\Router): void  \n\nIt will create all this routes:  \nGET  $prefixPath  \nGET / POST  $prefixPath . '/new'  \nGET / POST / DELETE $prefixPath . '/{id:\\d+}'  \n\n#### Setup Router and Routes with an array\n* setupRouterAndRoutesWithConfigArray(config: array): void  \n\nIn this example you can setup router's middlewares and routes with an array  \n```php\n$config = [\n    'router' =\u003e [\n        'middlewares' =\u003e [\n            'global_callback1',\n            'global_callback2',\n            'global_callback3'\n        ],\n        'constraints' =\u003e [\n            'lang' =\u003e 'en|fr'\n        ],\n        'host' =\u003e '{service}.domain.{tld}',\n        'host_constraint' =\u003e [\n            'service' =\u003e 'api|backoffice|www|m',\n            'tld' =\u003e 'en|jp'\n        ],\n        'default_404' =\u003e 'callable_404'\n    ],\n    'routes' =\u003e [\n        [\n            'methods' =\u003e ['GET'],\n            'url' =\u003e '/articles/{id}',\n            'callback' =\u003e 'route_callback',\n            'constraints' =\u003e ['id' =\u003e '\\w+'],\n            'middlewares' =\u003e ['route_middleware1', 'route_middleware2'],\n            'name' =\u003e 'route1'\n        ],\n        [\n            'methods' =\u003e ['POST'],\n            'url' =\u003e '/form',\n            'callback' =\u003e 'callback',\n        ],\n        [\n            'methods' =\u003e ['POST'],\n            'url' =\u003e '/api/form',\n            'callback' =\u003e 'callback',\n            'host' =\u003e 'api.domain.{tld}',\n            'host_constraint' =\u003e [\n                'tld' =\u003e 'en|jp'\n            ]\n        ],\n        [\n            'methods' =\u003e ['GET'],\n            'url' =\u003e '/blog/{page}',\n            'callback' =\u003e 'callback',\n            'optionals_parameters' =\u003e [\n                'page' =\u003e '1'\n            ]\n        ]\n    ]\n];\n\n$router = new Router();\n$router-\u003esetupRouterAndRoutesWithConfigArray($config);\n\n// you can add a Router as a callback\n$subRoute = new Router();\n$subRoute-\u003esetupRouterAndRoutesWithConfigArray($config);\n$router-\u003eany('/(.*)', $subRoute);\n```\n\n#### Get Routes\n* getRoutes(): \\Rancoud\\Router\\Route[]  \n\n#### Find route\n* findRoute(method: string, url: string, [host: string = null]): bool  \n* findRouteRequest(request: \\Psr\\Http\\Message\\ServerRequestInterface): bool  \n* getRouteParameters(): array  \n\n#### Run the found route \n* dispatch(request: \\Psr\\Http\\Message\\ServerRequestInterface): \\Psr\\Http\\Message\\Response  \n* handle(request: \\Psr\\Http\\Message\\ServerRequestInterface): \\Psr\\Http\\Message\\Response  \n\nThe difference between dispatch and handle is dispatch is used in first place.  \nHandle is from the PSR17 in Psr\\Http\\Message\\ServerRequestInterface, it's useful for middleware.  \n\n#### Middlewares\n* addGlobalMiddleware(middleware: \\Closure|\\Psr\\Http\\Server\\MiddlewareInterface|\\Rancoud\\Router\\Router|string): void  \n* setGlobalMiddlewares(middlewares: array): void  \n\n#### Global constraints\n* setGlobalParametersConstraints(constraints: array): void  \n* setGlobalHostConstraints(constraints: array): void  \n\n#### Generate url for a named route\n* generateUrl(routeName: string, [routeParameters: array = []]): ?string  \n\n#### Host constraints\n* setGlobalHost(host: string): void  \n\n#### Default 404\n* setDefault404(callback: mixed): void  \n\n## Route Constructor\n### Settings\n#### Mandatory\n| Parameter | Type                                                                                | Description                              |\n|-----------|-------------------------------------------------------------------------------------|------------------------------------------|\n| methods   | string \\| array                                                                     | methods matching with the route          |\n| url       | string                                                                              | url to match                             |\n| callback  | string \\| Closure \\| \\Psr\\Http\\Server\\MiddlewareInterface \\| \\Rancoud\\Router\\Router | callback when route is calling by router |\n\n## Route Methods\n### General Commands  \n#### Getters/Setters\n* getMethods(): array  \n* getUrl(): string  \n* getName(): string  \n* setName(name: string): void  \n\n#### Constraints\n* setParametersConstraints(constraints: array): void  \n* getParametersConstraints(): array  \n* compileRegex(globalConstraints: array): string  \n* setOptionalsParameters(optionalsParameters: array): void  \n* getOptionalsParameters(): array  \n\n#### Callback\n* getCallback(): mixed  \n\n#### Middlewares\n* addMiddleware(middleware: \\Closure|\\Psr\\Http\\Server\\MiddlewareInterface|\\Rancoud\\Router\\Router|string): array  \n* getMiddlewares(): array  \n\n#### Generate Url\n* generateUrl([routeParameters: array = []]): string  \n\n#### Host\n* getHost(): ?string  \n* setHost(host: string, [hostConstraints: array = []]): void  \n* setHostConstraints(constraints: array): void  \n* isSameHost(host: string, globalConstraints: array = []): bool  \n* getHostParameters(): array  \n\n## How to Dev\n`composer ci` for php-cs-fixer and phpunit and coverage  \n`composer lint` for php-cs-fixer  \n`composer test` for phpunit and coverage  \n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Francoud%2Frouter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Francoud%2Frouter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Francoud%2Frouter/lists"}