{"id":18771046,"url":"https://github.com/rareloop/router","last_synced_at":"2025-04-06T01:08:47.255Z","repository":{"id":46650440,"uuid":"97163634","full_name":"Rareloop/router","owner":"Rareloop","description":"A powerful PHP Router for PSR7 messages inspired by the Laravel API.","archived":false,"fork":false,"pushed_at":"2024-05-20T14:12:41.000Z","size":125,"stargazers_count":91,"open_issues_count":3,"forks_count":14,"subscribers_count":12,"default_branch":"master","last_synced_at":"2024-12-06T19:26:53.584Z","etag":null,"topics":["middleware","php-router","psr7","psr7-compliant","psr7-http","router"],"latest_commit_sha":null,"homepage":"","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/Rareloop.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-07-13T20:47:42.000Z","updated_at":"2024-07-17T10:18:06.000Z","dependencies_parsed_at":"2024-06-18T15:23:35.187Z","dependency_job_id":"6492c111-1079-4344-a480-e31715089677","html_url":"https://github.com/Rareloop/router","commit_stats":{"total_commits":77,"total_committers":7,"mean_commits":11.0,"dds":0.1428571428571429,"last_synced_commit":"0be4485e375aaf9d4c8db8009c59982a289e26cd"},"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Rareloop%2Frouter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Rareloop%2Frouter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Rareloop%2Frouter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Rareloop%2Frouter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Rareloop","download_url":"https://codeload.github.com/Rareloop/router/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247419860,"owners_count":20936012,"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":["middleware","php-router","psr7","psr7-compliant","psr7-http","router"],"created_at":"2024-11-07T19:22:59.356Z","updated_at":"2025-04-06T01:08:47.235Z","avatar_url":"https://github.com/Rareloop.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Rare Router\n[![Latest Stable Version](https://poser.pugx.org/rareloop/router/v/stable)](https://packagist.org/packages/rareloop/router)\n![CI](https://github.com/rareloop/router/actions/workflows/ci.yml/badge.svg?branch=master)\n[![Coverage Status](https://coveralls.io/repos/github/Rareloop/router/badge.svg)](https://coveralls.io/github/Rareloop/router)\n\nA simple PHP router built on [AltoRouter](https://github.com/dannyvankooten/AltoRouter) but inspired by the [Laravel](https://laravel.com/docs/5.4/routing) API.\n\n## Installation\n\n```\ncomposer require rareloop/router\n```\n\n## Usage\n\n### Creating Routes\n\n#### Map\n\nCreating a route is done using the `map` function:\n\n```php\nuse Rareloop\\Router\\Router;\n\n$router = new Router;\n\n// Creates a route that matches the uri `/posts/list` both GET \n// and POST requests. \n$router-\u003emap(['GET', 'POST'], 'posts/list', function () {\n    return 'Hello World';\n});\n```\n\n`map()` takes 3 parameters:\n\n- `methods` (array): list of matching request methods, valid values:\n    + `GET`\n    + `POST`\n    + `PUT`\n    + `PATCH`\n    + `DELETE`\n    + `OPTIONS`\n- `uri` (string): The URI to match against\n- `action`  (function|string): Either a closure or a Controller string\n\n#### Route Parameters\nParameters can be defined on routes using the `{keyName}` syntax. When a route matches that contains parameters, an instance of the `RouteParams` object is passed to the action.\n\n```php\n$router-\u003emap(['GET'], 'posts/{id}', function(RouteParams $params) {\n    return $params-\u003eid;\n});\n```\n\nIf you need to add constraints to a parameter you can pass a regular expression pattern to the `where()` function of the defined `Route`:\n\n```php\n$router-\u003emap(['GET'], 'posts/{id}/comments/{commentKey}', function(RouteParams $params) {\n    return $params-\u003eid;\n})-\u003ewhere('id', '[0-9]+')-\u003ewhere('commentKey', '[a-zA-Z]+');\n\n// or\n\n$router-\u003emap(['GET'], 'posts/{id}/comments/{commentKey}', function(RouteParams $params) {\n    return $params-\u003eid;\n})-\u003ewhere([\n    'id', '[0-9]+',\n    'commentKey', '[a-zA-Z]+',\n]);\n```\n\n#### Optional route Parameters\nSometimes your route parameters needs to be optional, in this case you can add a `?` after the parameter name:\n\n```php\n$router-\u003emap(['GET'], 'posts/{id?}', function(RouteParams $params) {\n    if (isset($params-\u003eid)) {\n        // Param provided\n    } else {\n        // Param not provided\n    }\n});\n```\n\n\n#### Named Routes\nRoutes can be named so that their URL can be generated programatically:\n\n```php\n$router-\u003emap(['GET'], 'posts/all', function () {})-\u003ename('posts.index');\n\n$url = $router-\u003eurl('posts.index');\n```\n\nIf the route requires parameters you can be pass an associative array as a second parameter:\n\n```php\n$router-\u003emap(['GET'], 'posts/{id}', function () {})-\u003ename('posts.show');\n\n$url = $router-\u003eurl('posts.show', ['id' =\u003e 123]);\n```\n\nIf a passed in parameter fails the regex constraint applied, a `RouteParamFailedConstraintException` will be thrown.\n\n#### HTTP Verb Shortcuts\nTypically you only need to allow one HTTP verb for a route, for these cases the following shortcuts can be used:\n\n```php\n$router-\u003eget('test/route', function () {});\n$router-\u003epost('test/route', function () {});\n$router-\u003eput('test/route', function () {});\n$router-\u003epatch('test/route', function () {});\n$router-\u003edelete('test/route', function () {});\n$router-\u003eoptions('test/route', function () {});\n```\n\n#### Setting the basepath\nThe router assumes you're working from the route of a domain. If this is not the case you can set the base path:\n\n```php\n$router-\u003esetBasePath('base/path');\n$router-\u003emap(['GET'], 'route/uri', function () {}); // `/base/path/route/uri`\n```\n\n#### Controllers\nIf you'd rather use a class to group related route actions together you can pass a Controller String to `map()` instead of a closure. The string takes the format `{name of class}@{name of method}`. It is important that you use the complete namespace with the class name.\n\nExample:\n\n```php\n// TestController.php\nnamespace \\MyNamespace;\n\nclass TestController\n{\n    public function testMethod()\n    {\n        return 'Hello World';\n    }\n}\n\n// routes.php\n$router-\u003emap(['GET'], 'route/uri', '\\MyNamespace\\TestController@testMethod');\n```\n\n### Creating Groups\nIt is common to group similar routes behind a common prefix. This can be achieved using Route Groups:\n\n```php\n$router-\u003egroup('prefix', function ($group) {\n    $group-\u003emap(['GET'], 'route1', function () {}); // `/prefix/route1`\n    $group-\u003emap(['GET'], 'route2', function () {}); // `/prefix/route2§`\n});\n```\n\n### Middleware\nPSR-15/7 Middleware can be added to both routes and groups.\n\n#### Adding Middleware to a route\nAt it's simplest, adding Middleware to a route can be done by passing an object to the `middleware()` function:\n\n```php\n$middleware = new AddHeaderMiddleware('X-Key1', 'abc');\n\n$router-\u003eget('route/uri', '\\MyNamespace\\TestController@testMethod')-\u003emiddleware($middleware);\n```\n\nMultiple middleware can be added by passing more params to the `middleware()` function:\n\n```php\n$header = new AddHeaderMiddleware('X-Key1', 'abc');\n$auth = new AuthMiddleware();\n\n$router-\u003eget('route/uri', '\\MyNamespace\\TestController@testMethod')-\u003emiddleware($header, $auth);\n```\n\nOr alternatively, you can also pass an array of middleware:\n\n```php\n$header = new AddHeaderMiddleware('X-Key1', 'abc');\n$auth = new AuthMiddleware();\n\n$router-\u003eget('route/uri', '\\MyNamespace\\TestController@testMethod')-\u003emiddleware([$header, $auth]);\n```\n\n#### Adding Middleware to a group\nMiddleware can also be added to a group. To do so you need to pass an array as the first parameter of the `group()` function instead of a string.\n\n```php\n$header = new AddHeaderMiddleware('X-Key1', 'abc');\n\n$router-\u003egroup(['prefix' =\u003e 'my-prefix', 'middleware' =\u003e $header]), function ($group) {\n    $group-\u003emap(['GET'], 'route1', function () {}); // `/my-prefix/route1`\n    $group-\u003emap(['GET'], 'route2', function () {}); // `/my-prefix/route2§`\n});\n```\n\nYou can also pass an array of middleware if you need more than one:\n\n```php\n$header = new AddHeaderMiddleware('X-Key1', 'abc');\n$auth = new AuthMiddleware();\n\n$router-\u003egroup(['prefix' =\u003e 'my-prefix', 'middleware' =\u003e [$header, $auth]]), function ($group) {\n    $group-\u003emap(['GET'], 'route1', function () {}); // `/my-prefix/route1`\n    $group-\u003emap(['GET'], 'route2', function () {}); // `/my-prefix/route2§`\n});\n```\n\n#### Defining Middleware on Controllers\nYou can also apply Middleware on a Controller class too. In order to do this your Controller must extend the `Rareloop\\Router\\Controller` base class.\n\nMiddleware is added by calling the `middleware()` function in your Controller's `__constructor()`.\n\n```php\nuse Rareloop\\Router\\Controller;\n\nclass MyController extends Controller\n{\n    public function __construct()\n    {\n        // Add one at a time\n        $this-\u003emiddleware(new AddHeaderMiddleware('X-Key1', 'abc'));\n        $this-\u003emiddleware(new AuthMiddleware());\n\n        // Add multiple with one method call\n        $this-\u003emiddleware([\n            new AddHeaderMiddleware('X-Key1', 'abc',\n            new AuthMiddleware(),\n        ]);\n    }\n}\n```\n\nBy default all Middleware added via a Controller will affect all methods on that class. To limit what methods Middleware applies to you can use `only()` and `except()`:\n\n```php\nuse Rareloop\\Router\\Controller;\n\nclass MyController extends Controller\n{\n    public function __construct()\n    {\n        // Only apply to `send()` method\n        $this-\u003emiddleware(new AddHeaderMiddleware('X-Key1', 'abc'))-\u003eonly('send');\n\n        // Apply to all methods except `show()` method\n        $this-\u003emiddleware(new AuthMiddleware())-\u003eexcept('show');\n\n        // Multiple methods can be provided in an array to both methods\n        $this-\u003emiddleware(new AuthMiddleware())-\u003eexcept(['send', 'show']);\n    }\n}\n```\n\n### Matching Routes to Requests\nOnce you have routes defined, you can attempt to match your current request against them using the `match()` function. `match()` accepts an instance of Symfony's `Request` and returns an instance of Symfony's `Response`:\n\n```php\n$request = Request::createFromGlobals();\n$response = $router-\u003ematch($request);\n$response-\u003esend();\n```\n\n#### Return values\nIf you return an instance of `Response` from your closure it will be sent back un-touched. If however you return something else, it will be wrapped in an instance of `Response` with your return value as the content.\n\n#### Responsable objects \nIf you return an object from your closure that implements the `Responsable` interface, it's `toResponse()` object will be automatically called for you.\n\n```php\nclass MyObject implements Responsable\n{\n    public function toResponse(RequestInterface $request) : ResponseInterface\n    {\n        return new TextResponse('Hello World!');\n    }\n}\n\n$router-\u003eget('test/route', function () {\n    return new MyObject();\n});\n```\n\n#### 404\nIf no route matches the request, a `Response` object will be returned with it's status code set to `404`;\n\n#### Accessing current route\nThe currently matched `Route` can be retrieved by calling:\n\n```php\n$route = $router-\u003ecurrentRoute();\n```\n\nIf no route matches or `match()` has not been called, `null` will be returned.\n\nYou can also access the name of the currently matched `Route` by calling:\n\n```php\n$name = $router-\u003ecurrentRouteName();\n```\n\nIf no route matches or `match()` has not been called or the matched route has no name, `null` will be returned.\n\n### Using with a Dependency Injection Container\nThe router can also be used with a PSR-11 compatible Container of your choosing. This allows you to type hint dependencies in your route closures or Controller methods.\n\nTo make use of a container, simply pass it as a parameter to the Router's constructor:\n\n```php\nuse MyNamespace\\Container;\nuse Rareloop\\Router\\Router;\n\n$container = new Container();\n$router = new Router($container);\n```\n\nAfter which, your route closures and Controller methods will be automatically type hinted:\n\n```php\n$container = new Container();\n\n$testServiceInstance = new TestService();\n$container-\u003eset(TestService::class, $testServiceInstance);\n\n$router = new Router($container);\n\n$router-\u003eget('/my/route', function (TestService $service) {\n    // $service is now the same object as $testServiceInstance\n});\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frareloop%2Frouter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frareloop%2Frouter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frareloop%2Frouter/lists"}