{"id":18080828,"url":"https://github.com/gigili/php-routing","last_synced_at":"2026-03-07T20:31:52.732Z","repository":{"id":41845007,"uuid":"283179764","full_name":"gigili/PHP-routing","owner":"gigili","description":"Custom PHP routing library especially useful for fast API development","archived":false,"fork":false,"pushed_at":"2024-08-22T19:17:55.000Z","size":399,"stargazers_count":7,"open_issues_count":5,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-09T11:04:55.176Z","etag":null,"topics":["dependency-injection","hacktoberfest","library","middleware","navigation","php","router","routing"],"latest_commit_sha":null,"homepage":"https://packagist.org/packages/gac/routing","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gigili.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":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-07-28T10:31:53.000Z","updated_at":"2025-03-05T00:17:11.000Z","dependencies_parsed_at":"2024-08-22T21:11:04.393Z","dependency_job_id":null,"html_url":"https://github.com/gigili/PHP-routing","commit_stats":{"total_commits":142,"total_committers":3,"mean_commits":"47.333333333333336","dds":"0.49295774647887325","last_synced_commit":"6740f18c5923234f59dff27f28c39d41087afcc6"},"previous_names":[],"tags_count":32,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gigili%2FPHP-routing","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gigili%2FPHP-routing/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gigili%2FPHP-routing/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gigili%2FPHP-routing/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gigili","download_url":"https://codeload.github.com/gigili/PHP-routing/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248581361,"owners_count":21128155,"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":["dependency-injection","hacktoberfest","library","middleware","navigation","php","router","routing"],"created_at":"2024-10-31T13:10:41.047Z","updated_at":"2026-03-07T20:31:52.680Z","avatar_url":"https://github.com/gigili.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Routing library for PHP\r\n\r\nThis library allows you to create static or dynamic routes. This library was inspired\r\nby [PHP Slim framework](https://www.slimframework.com/)\r\n\r\n[![PHP Tests](https://github.com/gigili/PHP-routing/actions/workflows/php-pest-tests.yml/badge.svg)](https://github.com/gigili/PHP-routing/actions/workflows/php-pest-tests.yml)\r\n[![License](https://poser.pugx.org/gac/routing/license)](https://packagist.org/packages/gac/routing)\r\n[![Total Downloads](https://poser.pugx.org/gac/routing/downloads)](https://packagist.org/packages/gac/routing)\r\n\r\n## Install via composer\r\n\r\n```shell\r\ncomposer require gac/routing\r\n```\r\n\r\n## Manual install\r\n\r\nDownload the latest release from the [Releases page](https://github.com/gigili/PHP-routing/releases).\r\n\r\nDon't forget to add these `include_once` statements to your php files:\r\n\r\n```php\r\ninclude_once \"./Exceptions/CallbackNotFound.php\";\r\ninclude_once \"./Exceptions/RouteNotFoundException.php\";\r\ninclude_once \"./Request.php\";\r\ninclude_once \"./Routes.php\";\r\n```\r\n\r\n## Post install\r\n\r\nTo use this library properly you will need to create a `.htaccess` file at the root of the project.\r\n\r\nExample of the `.htaccess` file would look like this:\r\n\r\n```apacheconf\r\nRewriteEngine On\r\n\r\nRewriteBase /\r\nRewriteCond %{REQUEST_FILENAME} !-f\r\nRewriteCond %{REQUEST_FILENAME} !-d\r\n\r\nRewriteRule ^(.+)$ index.php [QSA,L]\r\n```\r\n\r\n### Note\r\n\r\nIf you've named your main file differently, replace `index.php` in the `.htaccess` file with whatever your main\r\napplication file is.\r\n\r\n## Quick start\r\n\r\nSample code to allow you to quickly start with your development.\r\n\r\n```php\r\nuse Gac\\Routing\\Exceptions\\CallbackNotFound;\r\nuse Gac\\Routing\\Exceptions\\RouteNotFoundException;\r\nuse Gac\\Routing\\Request;\r\nuse Gac\\Routing\\Response;\r\nuse Gac\\Routing\\Routes;\r\n\r\ninclude_once \"vendor/autoload.php\"; # IF YOU'RE USING composer\r\n\r\n$routes = new Routes();\r\ntry {\r\n    $routes-\u003eadd('/', function (Request $request) {\r\n        // Old way of doing it, still supported until v4\r\n        $request\r\n            -\u003estatus(200, \"OK\")\r\n            -\u003esend([\"message\" =\u003e \"Welcome\"]);\r\n\r\n        // New way of doing it\r\n        Response::\r\n        withHeader(\"Content-Type\", \"application/json\")::\r\n        withStatus(200, 'OK')::\r\n        withBody([ \"message\" =\u003e \"Welcome\" ])::\r\n        send();\r\n    });\r\n    \r\n    $routes-\u003eroute('/', function (Request $request) {\r\n        // Old way of doing it, still supported until v4\r\n        $request\r\n            -\u003estatus(200, \"OK\")\r\n            -\u003esend([\"message\" =\u003e \"Welcome\"]);\r\n\r\n        // New way of doing it\r\n        Response::\r\n        withHeader(\"Content-Type\", \"application/json\")::\r\n        withStatus(200, 'OK')::\r\n        withBody([ \"message\" =\u003e \"Welcome\" ])::\r\n        send();\r\n    }, [Routes::POST])-\u003esave();\r\n\r\n    $routes-\u003eroute();\r\n} catch (RouteNotFoundException $ex) {\r\n    // Old way of doing it, still supported until v4\r\n    $routes-\u003erequest-\u003estatus(404, \"Route not found\")-\u003esend([\"error\" =\u003e [\"message\" =\u003e $ex-\u003egetMessage()]]);\r\n    \r\n    // New way of doing it\r\n    Response::withStatus(404, 'Route not found')::send([\"error\" =\u003e [ \"message\" =\u003e $ex-\u003egetMessage() ]]);\r\n} catch (CallbackNotFound $ex) {\r\n    // Old way of doing it, still supported until v4\r\n    $routes-\u003erequest-\u003estatus(404, \"Callback not found\")-\u003esend([\"error\" =\u003e [\"message\" =\u003e $ex-\u003egetMessage()]]);\r\n    \r\n    // New way of doing it\r\n    Response::withStatus(404, 'Callback not found')::send([\"error\" =\u003e [ \"message\" =\u003e $ex-\u003egetMessage() ]]);\r\n} catch (Exception $ex) {\r\n    $code = $ex-\u003egetCode() ?? 500;\r\n    \r\n    // Old way of doing it, still supported until v4\r\n    $routes-\u003erequest-\u003estatus($code)-\u003esend([\"error\" =\u003e [\"message\" =\u003e $ex-\u003egetMessage()]]);\r\n    \r\n    // New way of doing it\r\n    Response::withStatus($code)::send([\"error\" =\u003e [ \"message\" =\u003e $ex-\u003egetMessage() ]]);\r\n}\r\n```\r\n\r\n## Examples\r\n\r\n### Dynamic routes example\r\n\r\n```php\r\n$routes-\u003eadd('/test/{int:userID}-{username}/{float:amount}/{bool:valid}', function (\r\n    Request $request,\r\n    int $userID,\r\n    string $username,\r\n    float $amount,\r\n    bool $valid\r\n) {\r\n    echo 'Dynamic route content here';\r\n});\r\n```\r\n\r\n### Chained routes\r\n\r\nWhen using chained methods either use `-\u003esave()` or `-\u003eadd()` as the last method to indicate the end of a chain\r\n\r\n**NOTE**\r\n\r\n* `-\u003esave(true|false)` method can still be chained onto if needed\r\n  * Passing `false` (the default value is `true`) to the `-\u003esave()` method will preserve all the previous prefixes and middlewares in that chain\r\n* `-\u003eadd()` **CAN NOT** be chained onto and should be the last call in chain\r\n\r\n```php\r\n$routes\r\n    -\u003eprefix('/user') // all the routes added will have the /user prefix\r\n    -\u003emiddleware([ 'verify_token' ]) // all the routes added will have the verify_token middleware applied\r\n    -\u003eroute('/', [ HomeController::class, 'getUsers' ], Routes::GET)\r\n    -\u003eroute('/', [ HomeController::class, 'addUser' ], Routes::POST)\r\n    -\u003eroute('/', [ HomeController::class, 'updateUser' ], Routes::PATCH)\r\n    -\u003eroute('/', [ HomeController::class, 'replaceUser' ], Routes::PUT)\r\n    -\u003eadd('/test', [ HomeController::class, 'deleteUser' ], Routes::DELETE);\r\n```\r\n\r\n#### Chained routes with save at the end\r\n\r\n```php\r\n$routes\r\n    -\u003eprefix(\"/test\")\r\n    -\u003emiddleware(['decode_token'])\r\n    -\u003eroute(\"/t0\", function(Request $request){})\r\n    -\u003eget(\"/t1\", function (){})\r\n    -\u003epost(\"/t2\", function (){})\r\n    -\u003eput(\"/t3\", function (){})\r\n    -\u003epatch(\"/t4\", function (){})\r\n    -\u003edelete(\"/t5\", function (){})\r\n    -\u003esave();\r\n```\r\n\r\n#### Chained routes with multiple chains in one call\r\n\r\n```php\r\n$routes\r\n    -\u003eprefix(\"/test\")\r\n    -\u003emiddleware([ 'decode_token' ])\r\n    -\u003eget(\"/t1\", function () { }) // route would be: /test/t1\r\n    -\u003eget(\"/t2\", function () { }) // route would be: /test/t2\r\n    -\u003eget(\"/t3\", function () { }) // route would be: /test/t3\r\n    -\u003esave(false) // by passing the false argument here, we keep all the previous shared data from the chain (previous prefix(es) and middlewares)\r\n    -\u003eprefix(\"/test2\")\r\n    -\u003emiddleware([ \"verify_token\" ])\r\n    -\u003eget(\"/t4\", function () { }) // route would be: /test/test2/t4\r\n    -\u003eget(\"/t5\", function () { }) // route would be: /test/test2/t5\r\n    -\u003eget(\"/t6\", function () { }) // route would be: /test/test2/t6\r\n    -\u003esave() // by not passing the false argument here, we are removing all shared data from the previous chains (previous prefix(es) and middlewares)\r\n    -\u003eprefix(\"/test3\")\r\n    -\u003emiddleware([ \"verify_token\" ])\r\n    -\u003eget(\"/t7\", function () { }) // route would be: /test3/t7\r\n    -\u003eget(\"/t8\", function () { }) // route would be: /test3/t8\r\n    -\u003eget(\"/t9\", function () { }) // route would be: /test3/t9\r\n    -\u003eadd(); //using save or add at the end makes the chaining stop and allows for other independent routes to be added\r\n```\r\n\r\n### Passing arguments to middleware methods\r\n\r\nWhen working with middlewares you can also pass them arguments if you need to\r\n\r\n```php\r\nuse Gac\\Routing\\Response;\r\n\r\n$routes\r\n    -\u003emiddleware([\r\n        'test_middleware',\r\n        'has_roles' =\u003e 'admin,user',\r\n        [ Middleware::class, 'test_method' ],\r\n        [ Middleware::class, 'has_role', 'Admin', 'Moderator', [ 'User', 'Bot' ] ],\r\n    ])\r\n    -\u003eadd('/test', function (Request $request) {\r\n        // Old way of doing it, still supported until v4\r\n        $request-\u003esend([ 'msg' =\u003e 'testing' ]);\r\n        \r\n        //New way of doing it\r\n        Response::send([ \"msg\" =\u003e \"testing\" ]);\r\n    });\r\n```\r\n\r\nEvery middleware function can also accept an argument of type `Gac\\Routing\\Request` at any position as long as it has\r\nthe proper type specified.\r\n\r\n### Optional parameters\r\n\r\n```php\r\n$routes-\u003eadd(\r\n    '/demo/{id?}',\r\n    function($id = 'defaultValue'){\r\n    \techo \"ID: . $id\";\r\n    },\r\n    Routes::GET\r\n);\r\n```\r\n\r\nWhen calling this endpoint with `/demo` it will output `ID: defaultValue` and with `/demo/123` it will output `ID: 123`\r\n\r\n### Dependency injection on route classes\r\n\r\nWhen using classes to handle your route callback, and those classes have some dependencies that need to be injected\r\nthrough a constructor, you can specify them as an array of arguments to be injected or\r\nlet the library try to auto-inject classes.\r\n\r\n```php\r\n$routes-\u003eadd(\r\n    '/demo',\r\n    [ \r\n        HomeController::class, \r\n        'dependency_injection_test', \r\n        [ new InjectedClass() ] \r\n    ],\r\n    Routes::GET\r\n);\r\n```\r\n\r\nYou can also use named arguments or mix and match them\r\n\r\n```php\r\n$routes-\u003eadd(\r\n    '/demo',\r\n    [ \r\n        HomeController::class, \r\n        'dependency_injection_test', \r\n        [ \"injected_var\" =\u003e new InjectedClass(), new Middleware ] \r\n    ],\r\n    Routes::GET\r\n);\r\n```\r\n\r\nLetting the library auto-inject classes into the constructor\r\n\r\n```php\r\n$routes-\u003eadd(\r\n    '/demo',\r\n    [ InjectController::class ],\r\n    Routes::GET\r\n);\r\n```\r\n\r\n**NOTE**\r\n\r\nThe library will always try to auto-inject classes (***will skip ones with null as default value***) if non are\r\nprovided, and you're using a class for callbacks.\r\n\r\n### Use `__invoke` instead for single method classes\r\n\r\n```php\r\n$routes-\u003eadd(\r\n    '/invoke',\r\n    [ HomeController::class ],\r\n    Routes::GET\r\n);\r\n```\r\n\r\nYou can also use `__invoke` with dependency injection as well:\r\n\r\n```php\r\n$routes-\u003eadd(\r\n    '/invoke',\r\n    [ \r\n        HomeController::class, \r\n        [ new InjectedClass() ] \r\n    ],\r\n    Routes::GET\r\n);\r\n```\r\n\r\nFor more examples look in the [sample folder](/sample) `index.php` file\r\n\r\n## Documentation\r\n\r\nSource code documentation can be found at [PHP Routing documentation](https://gigili.github.io/PHP-routing/) page\r\n\r\n## Features\r\n\r\n* [x] Static routes\r\n* [x] Dynamic routes\r\n* [x] Dynamic routes with optional parameters\r\n* [x] Middlewares\r\n  * [x] Pass arguments to middlewares\r\n* [x] Route prefixes\r\n* [x] Method chaining\r\n* [x] Dependency injection on classes\r\n    * [x] Manual injection\r\n    * [x] Auto-injection","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgigili%2Fphp-routing","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgigili%2Fphp-routing","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgigili%2Fphp-routing/lists"}