{"id":32404808,"url":"https://github.com/coercive/router","last_synced_at":"2026-03-06T09:02:35.436Z","repository":{"id":56956331,"uuid":"62585919","full_name":"Coercive/Router","owner":"Coercive","description":"PHP Multilingual Router, compatible YAML, JSON, ARRAY, and can be reloaded by cache","archived":false,"fork":false,"pushed_at":"2026-02-24T11:30:27.000Z","size":171,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2026-02-24T16:38:42.308Z","etag":null,"topics":["multilingual","php","router","yaml"],"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/Coercive.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2016-07-04T20:16:58.000Z","updated_at":"2026-02-24T11:29:22.000Z","dependencies_parsed_at":"2023-12-06T16:28:24.306Z","dependency_job_id":"7eb03105-bf47-4858-bb0c-dd65fa2b0ffb","html_url":"https://github.com/Coercive/Router","commit_stats":{"total_commits":101,"total_committers":2,"mean_commits":50.5,"dds":0.4356435643564357,"last_synced_commit":"89ca8a80ec86ebe359ae8c8f79328cabf7adf786"},"previous_names":[],"tags_count":56,"template":false,"template_full_name":null,"purl":"pkg:github/Coercive/Router","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Coercive%2FRouter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Coercive%2FRouter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Coercive%2FRouter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Coercive%2FRouter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Coercive","download_url":"https://codeload.github.com/Coercive/Router/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Coercive%2FRouter/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30168608,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-06T07:56:45.623Z","status":"ssl_error","status_checked_at":"2026-03-06T07:55:55.621Z","response_time":250,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["multilingual","php","router","yaml"],"created_at":"2025-10-25T11:22:56.093Z","updated_at":"2026-03-06T09:02:35.378Z","avatar_url":"https://github.com/Coercive.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"Coercive Utility Router\n=======================\n\nA simple and multilingual yaml router.\n\nGet\n---\n```\ncomposer require coercive/router\n```\n\nExample YAML\n------------\n```yaml\nINDEX:\n    __: Projet\\Controller::Method\n    FR: /\n    EN: /\n\nHOME:\n    __: Projet\\Controller::Method\n    FR: accueil\n    EN: home\n\n###########################\n\n# {slug} can be all exept /\n# {nb} integer (three numbers) (custom regex)\n# {test} is optional (because brackets []) and like @abcdef ...\n\nBLOG:\n    __: Projet\\Controller::Method\n    FR: /{slug}/article-{nb:[0-9]{3}}[/{test:@[a-z]+}]\n    EN: /{slug}/post-{nb:[0-9]{3}}[/{test:@[a-z]+}]\n    options:\n        example: 'Hello World.'\n\n###########################\n\n# {id} integer (two numbers) (custom regex)\n# {name} can be all exept /\n# {script} can be all exept /\n\nCOMPLEX:\n    __: Projet\\Controller::Method\n    FR: chiffre-{id:[0-9]{2}}/nom-{name}/mechant-{script}\n    EN: number-{id:[0-9]{2}}/name-{name}/bad-{script}\n\n###########################\n\n# Multi optional inner same brackets !\n# {date} integer (optional)\n# {slug} can be all exept / (optional too)\n\nMULTI:\n    __: Projet\\Controller::Method\n    FR: fr/multi-optional[/{date:\\d+}-{slug}]\n    EN: en/multi-optional[/{date:\\d+}-{slug}]\n```\nThe \"__\" (double underscore) is what the router return when the route match.\nYou can set what information you want, basicaly the item to load.\nIn this example the router return a namespace / controller / method to launch.\n\nLoad\n----\n```php\nuse Coercive\\Utility\\Router\\Loader;\n\n# YAML\n\n# Load one routes file\n$router = Loader::loadByYaml('/path/routes.yml')\n# OR multi-files\n$router = Loader::loadByYaml(['/path/first_routes.yml', '/path/second_routes.yml', ...])\n\n# JSON\n\n# Load one routes file\n$router = Loader::loadByJson('/path/routes.json')\n# OR multi-files\n$router = Loader::loadByJson(['/path/first_routes.json', '/path/second_routes.json', ...])\n\n# ARRAY\n\n# Load routes array\n$router = Loader::loadByArray([\n    INDEX =\u003e [\n        '__' =\u003e 'Projet\\Controller::Method',\n        'FR' =\u003e '/',\n        'EN' =\u003e '/'\n    ],\n    HOME =\u003e [\n            '__' =\u003e 'Projet\\Controller::Method',\n            'FR' =\u003e 'accueil',\n            'EN' =\u003e 'home'\n    ],\n    [ ... ]\n])\n\n# CACHE\n\n# You can cache the prepared routes and re-inject them after\n# For example, you have cache in var $cache\n\nif( $cache-\u003eisCacheReady() ) {\n    # YES\n    # Load by cache\n    $data = $cache-\u003eget()\n    $router = Loader::loadByCache( $data )\n}\nelse {\n    # NO\n    # Classical Load\n    $router = Loader::loadByYaml( '/path/routes.yml' )\n}\n\n# /!\\ Important\n# On a previous page you have cached the prepared routes\n$cache-\u003eset( $router-\u003egetPreparedRoutesForCache() )\n\n# The second param in loader allow you to set a basepath before your routes\n# You can now use the router in local mode or ip with subdirectories before\n# Example : 000.000.00.00/folder/subfolder/my-custom-route/my-param\n$router = Loader::loadByArray([...], '/folder/subfolder')\n\n# If you don't use the loader :\n$parser-\u003esetBasePath('/folder/subfolder')\n\n# OPTIONAL CONFIG PREFIX for loadByYaml or loadByJson\n# (if use loadByArray : you have to set it yourself)\n$router = Loader::loadByYaml([\n\t'/path/routes.yml',\n\t'SHOP_' =\u003e '/other-directory/shop/path/routes.yml',\n\t'BLOG_' =\u003e '/other-directory/blog/path/routes.yml'\n]);\n# (the first route has no prefix, the others ID : SHOP_... and BLOG_...)\n\n```\n\nStart the router\n----------------\nWhen config is loaded, start the router if you wan't to handle current route.\n```php\n\u003c?php\n# Start\n$router-\u003erun();\n```\n\nBasic Functions\n---------------\n```php\n#\n# Important: don't forget to start the router before use current route...\n#\n    // Get ID : (example : INDEX)\n    $router-\u003ecurrent()-\u003egetId()\n\n    // Get LANG : (example : EN)\n    $router-\u003ecurrent()-\u003egetLang()\n\n    // Get Controller : (example : Projet\\Controller::Method)\n    $router-\u003ecurrent()-\u003egetController()\n\n    // Get ALL Options : (array)\n    $router-\u003ecurrent()-\u003egetOptions()\n\n    // Get ONE Option : (example on BLOG route)\n    $router-\u003ecurrent()-\u003egetOption('example')\n\n    // Force LANG : (example : EN)\n    // If your process requires it, you can change the internal language\n    // For example : when no route founded for current uri (404)\n    $router-\u003ecurrent()-\u003esetLang('EN')\n    // or you can set a default lang in the constructor for the empty route)\n\n    // Get HOST : (example : www.my-website.test)\n    $router-\u003egetHost()\n\n    // Force HOST : (example : www.my-new-domaine-name.test)\n    // If your process requires it, you can change the host name\n    // Useful for url builder\n    $router-\u003esetHost('www.my-new-domaine-name.test')\n\n    // Force SCHEME : (example : https://)\n    // If your process requires it, you can change the protocol scheme\n    // Useful for url builder\n    $router-\u003esetProtocol('//')\n\n    // To apply your new host on base url, use setBaseUrl with no param\n    $router-\u003esetBaseUrl();\n\n    // To overwrite current base url with custom one\n    $router-\u003esetBaseUrl('https://www.my-new-domaine-name.test');\n\n#\n# Util methods :\n#\n    // Get Access Mode : (example : GET, POST ...)\n    $router-\u003egetMethod()\n\n    // Get HTTP Mode : (http / https)\n    $router-\u003egetProtocol()\n\n    // Get Server Script Uri\n    $router-\u003egetScriptUri()\n\n    // Get Server Script Url\n    $router-\u003egetScriptUrl()\n\n    // Detect ajax request\n    $router-\u003eisAjaxRequest()\n\t\n    // Manually set ajax request\n    $router-\u003esetAjaxRequest(true|false)\n\n    // Get what data accepted : (example : json, xml ...)\n    $router-\u003egetHttpAccept()\n\n    // Get current url\n    $router-\u003egetCurrentURL() // xss filtered\n    $router-\u003egetRawCurrentURL() // raw\n\n    // Get server doc_root\n    $router-\u003egetServerRootPath()\n```\n\nSwitch Language\n---------------\n```php\n#\n# Switch lang for the current url\n#\n    # BLOG example\n    # /{slug}/article-{nb:[0-9]{3}}[/{test:@[a-z]+}]\n\n    // Get basic current url path for FR language\n    $router-\u003eswitchLang('FR')\n\n        /* blog-title/article-789 */\n\n    // Same with the full path option\n    $router-\u003eswitchLang('FR', true)\n\n        /* http://www.my-web-site.example/blog-title/article-789 */\n\n\n#\n# OVERLOAD CURRENT URLPATH DATA\n#\n    // Create a new slug and add the optional test var (blog route)\n    $router-\u003eoverloadParam([\n        'EN' =\u003e [\n            'slug' =\u003e 'my-new-slug',\n            'test' =\u003e '@example'\n        ]\n    ]);\n\n    // You can prepare all data in one place\n    $router-\u003eoverloadParam([\n        'EN' =\u003e [...],\n        'FR' =\u003e [...],\n        'RU' =\u003e [...]\n    ]);\n\n    // OR separately in multi places\n    $router-\u003eoverloadParam([\n        'EN' =\u003e [...]\n    ]);\n    # ... some code\n    $router-\u003eoverloadParam([\n        'FR' =\u003e [...]\n    ]);\n    # ... some code\n    $router-\u003eoverloadParam([\n        'RU' =\u003e [...]\n    ]);\n    # ... some code\n\n    // Now, when get the swithed path :\n    $router-\u003eswitchLang('EN')\n\n        /* my-new-slug/article-789/@example */\n\n\n#\n# You can reset overload params\n#\n    $router-\u003eresetOverload();\n\n    // Now, when get the swithed path, it returns the original params\n    $router-\u003eswitchLang('EN')\n\n        /* blog-title/article-789 */\n\n```\n\nSwitch\n------\n```php\n#\n# Switch params for the current url\n#\n    # SEARCH example\n    # /search-article?q=hello\u0026page=1\n\n    // Rewrite only the page in french\n    $router-\u003eswitch('FR', [], ['page' =\u003e 2]);\n\n        /* /recherche-un-article?q=hello\u0026page=2 */\n\n \t# BLOG example\n    # /article-42?option=pdf\u0026page=2\n\n\t// Rewrite id in same lang\n    $router-\u003eswitch('', ['id' =\u003e 55]);\n\n        /* /article-55?option=pdf\u0026page=2 */\n\t\t\n\t// Delete specific query item\n    $router-\u003eswitch('', [], ['option' =\u003e null]);\n\n        /* /article-42?page=2 */\n\n# etc...\n\n```\n\nBuild URL\n---------\n```php\n#\n# BASIC URL\n#\n$router-\u003eurl('HOME') // current language\n$router-\u003eurl('HOME', null) // current language\n$router-\u003eurl('HOME', 'EN') // EN language\n\n#\n# For the next examples, i use the blog route\n# /{slug}/article-{nb:[0-9]{3}}[/{test:@[a-z]+}]\n#\n\n# example-fabric-url/article-100\n$router-\u003eurl('BLOG', 'FR', ['slug'=\u003e'example-fabric-url', 'nb'=\u003e100])\n\n# Full scheme autodetect (true | 'auto') or manually set\n$router-\u003eurl('BLOG', 'FR', ['slug'=\u003e'example-fabric-url', 'nb'=\u003e100], null, true)\n\n# http://www.my-web-site.com/example-fabric-url/article-100\n$router-\u003eurl('BLOG', 'FR', ['slug'=\u003e'example-fabric-url', 'nb'=\u003e100], null, 'http')\n\n# https://www.my-web-site.com/example-fabric-url/article-100\n$router-\u003eurl('BLOG', 'FR', ['slug'=\u003e'example-fabric-url', 'nb'=\u003e100], null, 'https')\n\n# ftp://www.my-web-site.com/example-fabric-url/article-100\n$router-\u003eurl('BLOG', 'FR', ['slug'=\u003e'example-fabric-url', 'nb'=\u003e100], null, 'ftp')\n\n# https://custom-domain.com/example-fabric-url/article-100\n$router-\u003eurl('BLOG', 'FR', ['slug'=\u003e'example-fabric-url', 'nb'=\u003e100], null, 'https://custom-domain.com')\n\n# example-fabric-url/article-100?param1=test1\u0026param2=test2\n$router-\u003eurl('BLOG', 'FR', ['slug'=\u003e'example-fabric-url', 'nb'=\u003e100], ['param1'=\u003e'test1', 'param2'=\u003e'test2'])\n\n#\n# With Route object\n#\necho $router-\u003eroute('BLOG', 'FR')\n    -\u003esetRewriteParams([\n        'slug'=\u003e'example-fabric-url',\n         'nb'=\u003e100\n     ])\n     -\u003esetQueryParams([\n        'param1'=\u003e'test1',\n        'param2'=\u003e'test2'\n    ])\n    -\u003esetBaseUrl('https://custom-domain.com')\n    -\u003esetFullScheme(true)\n;\n```\n\nFind\n----\n```php\n\u003c?php\n# You may need to find a route relative to a specific url which is not the current url.\n$example_referer_url = (string) filter_input(INPUT_SERVER, 'HTTP_REFERER', FILTER_SANITIZE_STRING);\n$route = $router-\u003efind($example_referer_url);\necho $route-\u003egetId();\n```\n\nFilter\n------\n```php\n\u003c?php\n# For this example, we use the BLOG entry in the previous sample yaml.\n#   options:\n#       example: 'Hello World.'\n$f = new Filter;\n$f-\u003eoptions('example', 'Hello World.', 'string'); # third parameter is optional\n\n$routes = $router-\u003efilter($f);\n\nforeach ($routes as $route) {\n    echo $route-\u003egetId() . ' - ' . $route-\u003egetOption('example') . '\u003cbr\u003e';\n}\n```\n\nLoad Controller\n---------------\n```php\n#\n# Class\n#\n$ctrl = new Ctrl;\n\n#\n# Set default controller\n#\n$ctrl-\u003esetDefault('Error500\\\\CtrlName::MethodName');\n\n#\n# Set App\n# (Object optional : Example\\\\CtrlName-\u003eMethodName(\u003e Param App \u003c))\n#\n$ctrl-\u003esetApp(new App);\n\n#\n# Load\n#\n$ctrl-\u003eload('Example\\\\MyController::HomePage');\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoercive%2Frouter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcoercive%2Frouter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoercive%2Frouter/lists"}