{"id":22314391,"url":"https://github.com/undercloud/beacon","last_synced_at":"2025-03-26T02:46:06.849Z","repository":{"id":57075257,"uuid":"63795053","full_name":"undercloud/beacon","owner":"undercloud","description":"PHP Routing System","archived":false,"fork":false,"pushed_at":"2023-10-03T09:41:39.000Z","size":97,"stargazers_count":1,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-31T00:18:21.613Z","etag":null,"topics":["manage","middleware","route","routing","url"],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/undercloud.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-07-20T16:02:03.000Z","updated_at":"2021-10-16T19:13:55.000Z","dependencies_parsed_at":"2022-08-24T14:55:41.427Z","dependency_job_id":null,"html_url":"https://github.com/undercloud/beacon","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/undercloud%2Fbeacon","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/undercloud%2Fbeacon/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/undercloud%2Fbeacon/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/undercloud%2Fbeacon/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/undercloud","download_url":"https://codeload.github.com/undercloud/beacon/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245579582,"owners_count":20638676,"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":["manage","middleware","route","routing","url"],"created_at":"2024-12-03T22:09:54.135Z","updated_at":"2025-03-26T02:46:06.832Z","avatar_url":"https://github.com/undercloud.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Beacon - PHP Routing System\n[![Build Status](https://travis-ci.com/undercloud/beacon.svg?branch=master)](https://travis-ci.com/undercloud/beacon)\n\n## Features\n- Zero dependency\n- PCRE pattern path support\n- Route groups\n- Domain condition support\n- HTTPS condition support\n- Controller bindings\n- RESTful\n- Unicode\n- Wildcard attributes\n- Auth\n\n## Requirements\nPHP 5.4+\n\n## Installation\n`composer require undercloud/beacon`\n\n## .htaccess\nPretty URLs with .htaccess:\n```\nRewriteEngine On\nRewriteCond   %{REQUEST_FILENAME}       !-d\nRewriteCond   %{REQUEST_FILENAME}       !-f\nRewriteRule   ^(.*) index.php?%{QUERY_STRING}\n```\n\n## Setup\n```PHP\n// if installed by composer\nrequire '/path/to/vendor/autoload.php';\n// if installed manually\nrequire '/path/to/Beacon/Beacon.php';\n\n$router = new Beacon\\Router([\n  // current hostname\n  'host' =\u003e $_SERVER['SERVER_NAME'],\n  // current http method\n  'method' =\u003e $_SERVER['REQUEST_METHOD'],\n  // optionaly, true if request over https\n  'isSecured' =\u003e true\n]);\n```\n\n## Concept\nThe API is built on the principle of a \nhttps://en.wikipedia.org/wiki/Fluent_interface\n\n## Define routes\nHere's a basic usage example:\n```PHP\n$router\n  // any of methods get,post,put or delete\n  -\u003eon('/', 'Controller::index')\n  // only get method\n  -\u003eget('/user/:id', 'ControllerUser::getUser')\n  // only post\n  -\u003epost('/user/:id', function () { ... })\n  // fallback function\n  -\u003eotherwise(function() {\n    echo 404;\n  });\n\n// resolve request\n$route = $router-\u003ego($_SERVER['REQUEST_URI']);\n```\n\n`Beacon\\Router::go` method return `Beacon\\Route` instance with next methods:\n```PHP\n// route path\n$route-\u003egetPath();\n// get callback\n$route-\u003egetCallback();\n// get binded params\n$route-\u003egetParams();\n// get middlewares list\n$route-\u003egetMiddleware();\n```\n\n### Unicode paths\nRoute paths can contain any Unicode character set\n```PHP\n$router-\u003eon('/gâteau-français', function () { ... })\n```\n\n### Methods\nComplete list of avail route methods\n```PHP\n/*\n * $path - request path, example /users, support PCRE\n * $call - callback, string 'Controller::action' or Closure\n * $methods - array of http methods, example ['post','put']\n */\n\n$router-\u003eon($path, $call);\n$router-\u003eget($path, $call);\n$router-\u003epost($path, $call);\n$router-\u003eput($path, $call);\n$router-\u003edelete($path, $call);\n$router-\u003epatch($path, $call);\n$router-\u003ehead($path, $call);\n$router-\u003ematch(array $methods, $path, $call);\n```\n\n### Params\nBeacon supports named params.\nFor example, route with binded params:\n```PHP\n$router-\u003eon('/user/:id/:name(/:nickname)', 'ControllerUser::getUser');\n```\nfrom request:\n```PHP\n$route = $router-\u003ego('/user/78/John');\n```\nwill be fetched into:\n```PHP\n[\n  'id'       =\u003e 78,\n  'name'     =\u003e 'John',\n  'nickname' =\u003e null\n]\n```\nYou can also add additional check for params:\n```PHP\n$router\n  -\u003eon('/user/:id/:name(/:nickname)', 'ControllerUser::getUser')\n    // check numeric id\n    -\u003ewithWhere('id', '/\\d+/')\n    // empty or invalid nickname will be replaced with 'Guest'\n    -\u003ewithWhere('nickname', '/[A-Za-z0-9]+/', 'Guest')\n  -\u003eon(...);\n```\nNow params will be fetched into:\n```PHP\n[\n  'id'       =\u003e 78,\n  'name'     =\u003e 'John',\n  'nickname' =\u003e 'Guest'\n]\n```\nFor retrieve params use `$route-\u003egetParams()`\n\n### Wildcard Attributes\nSometimes it is useful to allow the trailing part of the path be anything at all.\nTo allow arbitrary trailing path segments on a route, call the wildcard() method.\nThis will let you specify the attribute name under which the arbitrary trailing\nvalues will be stored.\n```PHP\n$router\n  -\u003eon('/foo', function() { ... })\n    -\u003ewildcard('card')\n  -\u003eon('/bar', function() { ... });\n\n$route = $router-\u003ego('/foo/bar/baz/quux');\n\n// ['card' =\u003e ['bar','baz','quux']]\n$params = $route-\u003egetParams();\n```\n\n### Otherwise\nIf request cannot be resolved, you can define fallback:\n```PHP\n$router\n  -\u003eotherwise(function(){\n    switch(Beacon\\RouterError::getErrorCode()){\n      case Beacon\\RouterError::NOT_FOUND_ERROR:\n      /* Same as 404 error, cannot find any path for current request */\n      break;\n\n      case Beacon\\RouterError::SECURE_ERROR:\n      /* Need secured connection over https */\n      break;\n\n      case Beacon\\RouterError::CONTROLLER_RESOLVE_ERROR:\n      /* When given method in binded contoller is unavailable */\n      break;\n\n      case Beacon\\RouterError::WHERE_REGEX_ERROR:\n      /* Fail parameter regex test in -\u003ewhere(...) */\n      break;\n\n      case Beacon\\RouterError::REST_RESOLVE_ERROR:\n      /* Cannot find implemented method in given REST controller*/\n      break;\n\n      case Beacon\\RouteError::AUTH_ERROR:\n      /* Auth check failed */\n      break;\n    }\n  });\n```\n\n### Controller\nYou can define controller namespace and bind methods to path:\n```PHP\n// bind path to controller\n$router-\u003econtroller('/users', 'ControllerUsers');\n// resolve\n$route = $router-\u003ego('/users/get-users');\n// will return ControllerUsers::getUsers\n$call = $route-\u003egetCallback();\n```\nIf requested method undefined or is not public, Beacon return fallback function.\n\n### Group\nRoutes can be grouped:\n```PHP\n$router-\u003egroup('/api', function ($router) {\n  $router-\u003eget('/users', 'ControllerUsers::getUsers')\n});\n\n$route = $router-\u003ego('/api/users');\n...\n```\ngroups can be nested:\n```PHP\n$router-\u003egroup('/api', function ($router) {\n  $router-\u003egroup('/v1.1' function($router) {\n    $router-\u003eget('/users', 'ControllerUsers::getUsers')\n  });\n});\n```\n\n### Domain\nIf your app can de accessed from  multiple hostnames, you can setup personal routes for each domains:\n```PHP\n$router\n  -\u003edomain('api.example.com', function ($router) {\n    $router-\u003eget('/', function () {\n      echo 'api';\n    });\n  })\n  -\u003eget('/', function () {\n    echo 'main domain';\n  });\n```\n\n### REST\nIt so easy to make RESTfull service, define path:\n```PHP\n$router-\u003eresource(\n  '/photo',\n  'ControllerPhoto', \n  // define param name, default 'id'\n  $paramName' = 'photo'\n);\n```\nand define controller with specific methods:\n```PHP\nclass ControllerPhoto\n{\n  // build list\n  public function index()\n  {\n    ...\n  }\n\n  // build form\n  public function create()\n  {\n    ...\n  }\n\n  // save form\n  public function store()\n  {\n    ...\n  }\n  ...\n}\n```\nNext table show conformity between request path and controller methods:\n\n|Verb\t|Path\t\t\t\t\t|Action |Call\n|-------|-----------------------|-------|-------------------------\n|GET\t|/photo\t\t\t\t\t|index  |ControllerPhoto::index\n|GET\t|/photo/create\t\t\t|create\t|ControllerPhoto::create\n|POST\t|/photo\t\t\t\t\t|store\t|ControllerPhoto::store\n|GET\t|/photo/:photo\t\t\t|show\t|ControllerPhoto::show\n|GET\t|/photo/:photo/edit\t|edit\t|ControllerPhoto::edit\n|PUT\t|/photo/:photo\t\t\t|update\t|ControllerPhoto::update\n|DELETE\t|/photo/:photo\t\t\t|destroy|ControllerPhoto::destroy\nNote, that if requested method undefined or is not public, Beacon return fallback function.\n\n## Route options\nAll methods:\n\n* on\n* get\n* post\n* put\n* delete\n* patch\n* head\n* match\n* controller\n* group\n* domain\n* resource\n\ncan be additionaly setuped with next methods:\n\n* withSecure - secure settings\n* withMiddleware, withoutMiddleware, withoutAnyMiddleware - manage middleware chain\n* withAuth - access checker\n\nOptions defined in parent sections, will be inherited by childs, e.g.:\n```PHP\n$router\n  -\u003egroup('/api', function ($router) {\n    // now in inherit options defined in group\n    $router-\u003eget('/users/:id', function() {...});\n  })\n    -\u003ewithSecure(true),\n    -\u003ewithMiddleware(['MiddlewareAuth','MiddlewareCompressor'])\n  -\u003egroup('/another-group', ...);\n```\n\nYou can override inherited, just define personal:\n```PHP\n$router-\u003egroup('/api', function ($router) {\n  // now in inherit options defined in group\n  $router-\u003eget('/users/:id', function() {...})\n    -\u003ewithSecure(false);\n})\n  -\u003ewithSecure(true)\n  -\u003ewithMiddleware(['MiddlewareAuth','MiddlewareCompressor']);\n```\nFor defining global pre-setuped options use `Beacon\\Router::globals(array $options)`.\n```PHP\n$router\n  -\u003eglobals()\n    withSecure(true)\n    withMiddleware(['MiddlewareAuth'])\n  // inherit global options\n  -\u003eget('/', 'Controller::index')\n  // override global\n  -\u003epost('/users', 'ControllerUsers::getUsers')\n    -\u003ewithSecure(false)\n```\n\n## Middleware chain\nBeacon makes it easy to manage the chain of middlewares, look at this example:\n```PHP\n$router\n  -\u003eglobals()\n    -\u003ewithMiddleware('MiddlewareAuth')\n  -\u003eon('/', function() { ... })\n  -\u003egroup('/api', function ($router) {\n    $router-\u003eon('/guest', 'ControllerApi::getGuests')\n      withoutMiddleware('MiddlewareAuth')\n      withMiddleware('MiddlewareGuest');\n\n    $router-\u003eon('/secure')\n      -\u003ewithoutAnyMiddleware()\n      -\u003ewithMiddleware('MiddlewareSecure');\n  })\n    -\u003ewithMiddleware('MiddlewareApi');\n```\nNow middleware stack for:\n   * `/` is `['MiddlewareAuth','MiddlewareApi']`\n   * `/api/guest` is `['MiddlewareApi','MiddlewareGuest']`\n   * `/api/secure` is `['MiddlewareSecure']`\n\n## Secure\nIf you wanna routes, that must be handle over https only, setup it like this:\n```PHP\n$router\n  -\u003eget('/pay', 'System::pay')\n    -\u003ewithSecure(true)\n```\n\n## Auth\nYou can assign callback for access check:\n```PHP\n$router\n  -\u003eget('/dashboard', 'System::dashboard')\n  -\u003ewithAuth('User::isAdmin')\n```\nOr for high level methods `group`, `domain`, `controller`, `rest`:\n```PHP\n$router\n  -\u003egroup('/api', function(){\n    ...\n    })\n      -\u003ewithAuth('Api::checkKey')\n```\n\n## Error Handling\nsee [Otherwise section](https://github.com/undercloud/beacon#otherwise)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fundercloud%2Fbeacon","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fundercloud%2Fbeacon","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fundercloud%2Fbeacon/lists"}