{"id":15579394,"url":"https://github.com/inanepain/routing","last_synced_at":"2025-04-24T01:28:01.649Z","repository":{"id":52489034,"uuid":"500237918","full_name":"inanepain/routing","owner":"inanepain","description":"HTTP Routing using attributes.","archived":false,"fork":false,"pushed_at":"2025-03-02T11:55:50.000Z","size":38,"stargazers_count":1,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"develop","last_synced_at":"2025-03-30T05:41:10.088Z","etag":null,"topics":["inane","library","php","routing"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"unlicense","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/inanepain.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"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":"2022-06-05T23:43:19.000Z","updated_at":"2024-12-25T20:10:27.000Z","dependencies_parsed_at":"2024-12-25T19:23:02.645Z","dependency_job_id":"f844733f-4148-4575-943c-42588c41e7aa","html_url":"https://github.com/inanepain/routing","commit_stats":{"total_commits":11,"total_committers":2,"mean_commits":5.5,"dds":"0.18181818181818177","last_synced_commit":"217abdc1bdd2a6495f053000aeafbd76cf6598fc"},"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/inanepain%2Frouting","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/inanepain%2Frouting/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/inanepain%2Frouting/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/inanepain%2Frouting/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/inanepain","download_url":"https://codeload.github.com/inanepain/routing/tar.gz/refs/heads/develop","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250543289,"owners_count":21447865,"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":["inane","library","php","routing"],"created_at":"2024-10-02T19:14:45.208Z","updated_at":"2025-04-24T01:28:01.624Z","avatar_url":"https://github.com/inanepain.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Readme: Routing\n\n\u003e $Id$ ($Date$)\n\nHTTP Routing using php **Attributes**.\n\nNOTE: examples updated to use RouteMatch.\n\n## Intro: Attributes\n\nWhat is an **Attribute**? It's a class just like any other class only with the `Attribute` **Attribute**. So why are you treating it more like an `enum` or `Map` that can only hold a few values describing something? You don't do it with the classes you uses your custom attributes on! But I don't blame you, it all comes down to some pour choices in wording used by the documentation.\n\nSo how should I be think of **Attributes**? As classes naturally. Classes to object that get things done to be more exact. That `#[Route(name: 'home', path: '/')]` like might make more sense when you start looking at it like this: `$route = new Route('/', 'home');`. Here a fun experiment to try; remove the `Attribute` from `Route` then have the `Router` take an array of `Route` parameters as argument. Easy, wasn't it and you understand Attributes and with practice you spot many more classes you can use as such.\n\nHope that gets you thinking about **Attributes** in a new, more realistic manor that leads to you adding that `#[Attribute]` line to a good many more classes.\n\n## Install\n\n`composer require inanepain/routing`\n\n## Usage\n\nQuick overview showing the bits relating to the `Route` `Attribute` in two examples. Neither are complete, though the simple example would run with minimum fuss. Check the Appendix for the `.htaccess` file you will need to use with the `index.php` file.\n\n## Example: Simple\n\nSuper simple example using **php** built in web server, `php -S localhost:8080 -t public index.php`.\n\n**MainController.php:**\n\n```php\nclass MainController {\n    ...\n\n    #[Route(path: '/', name: 'home')]\n    public function home(): void {\n        ...\n        echo \u003c\u003c\u003cHTML\n...\nHTML;\n    }\n\n    ...\n\n    #[Route(path: '/product/{product}', name: 'product', )]\n    public function productTask(array $params): void {\n        $sql = \"...where product_id = '{$params[\"product\"]}'\";\n        ...\n        echo \u003c\u003c\u003cHTML\n...\nHTML;\n    }\n\n    ...\n}\n```\n\n**index.php:**\n\n```php\nuse App\\Controller\\MainController;\nuse Inane\\Routing\\Router;\n\nrequire_once 'vendor/autoload.php';\n\n$file = 'public' . $_SERVER['REQUEST_URI'];\n\n// Server existing files in web dir\nif (file_exists($file) \u0026\u0026 !is_dir($file)) return false;\n\n$router = new Router();\n$router-\u003eaddRoutes([MainController::class]);\n\nif ($match = $router-\u003ematch()) {\n    $controller = new $match-\u003eclass();\n    $controller-\u003e{$match-\u003emethod}($match-\u003eparams);\n} else {\n    throw new Exception('Request Error: Unmatched `file` or `route`!');\n}\n\n```\n\n## Example: Application\n\nSlightly more complex example.\n\n#### The various pieces\n\n**IndexController.php:**\n\n```php\nclass IndexController extends AbstractController {\n    ...\n\n    #[Route(path: '/', name: 'home')]\n    public function indexTask(): array {\n        ...\n    }\n\n    ...\n\n    #[Route(path: '/product/{product}', name: 'product', )]\n    public function productTask(): array {\n        ...\n    }\n\n    ...\n\n    #[Route(path: '/product/{product}/review/{id\u003c\\d+\u003e}', name: 'product-review')]\n    public function reviewTask(): array {\n        ...\n    }\n\n    ...\n}\n```\n\n**index.phtml (view template):**\n\n```phtml\n...\n\u003ca class=\"menu-item\" href=\"\u003c?=$route-\u003eurl('product', ['product' =\u003e $item['id']])?\u003e\"\u003e\u003c?=$item['name_long']?\u003e\u003c/a\u003e\n...\n```\n\n**website (rendered view):**\n\n```html\n\u003ca class=\"menu-item\" href=\"/product/mega-maid\"\u003eMega Maid (Household Robot Helper)\u003c/a\u003e\n```\n\n#### Putting it all together\n\n**Application.php:**\n\n```php\nclass Application {\n    ...\n\n    protected function initialise(): void {\n        ...\n        $this-\u003erouter = new Router([\n            IndexController::class,\n            ...\n            WhoopsController::class,\n            ...\n        ]);\n        ...\n    }\n\n    ...\n\n    public function run(): void {\n        ...\n        if ($match = $this-\u003erouter-\u003ematch()) {\n            $controller = new $match-\u003eclass($match['params']);\n            $data = $controller-\u003e{$match['method']}();\n            ...\n            // since 1.4.0: using the RouteMatch we can now easily get the template\n            $body = $this-\u003erenderer-\u003erender($match-\u003etemplate, $data);\n            ...\n        }\n        ...\n    }\n\n    ...\n}\n```\n\n## Appendix: .htaccess\n\nYou will also need to do some magic in your `.htaccess` file so that `index.php` handles all requests.\n\n```appache\nRewriteEngine On\n# The following rule tells Apache that if the requested filename exists, simply serve it.\nRewriteCond %{REQUEST_FILENAME} -s [OR]\nRewriteCond %{REQUEST_FILENAME} -l [OR]\nRewriteCond %{REQUEST_FILENAME} -d\nRewriteRule ^.*$ - [L]\n\n# The following rewrites all other queries to index.php. The\n# condition ensures that if you are using Apache aliases to do\n# mass virtual hosting or installed the project in a subdirectory,\n# the base path will be prepended to allow proper resolution of\n# the index.php file; it will work in non-aliased environments\n# as well, providing a safe, one-size fits all solution.\nRewriteCond %{REQUEST_URI}::$1 ^(/.+)/(.*)::\\2$\nRewriteRule ^(.*) - [E=BASE:%1]\nRewriteRule ^(.*)$ %{ENV:BASE}/index.php [L]\n\n\u003cLimit GET HEAD POST PUT DELETE OPTIONS\u003e\n# Deprecated apache 2.2 syntax:\n# Order Allow,Deny\n# Allow from all\n# Apache \u003e 2.4 requires:\nRequire all granted\n\u003c/Limit\u003e\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Finanepain%2Frouting","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Finanepain%2Frouting","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Finanepain%2Frouting/lists"}