This commit is contained in:
William 2023-03-21 21:41:02 +01:00
commit d60e072010
5 changed files with 223 additions and 0 deletions

13
LICENSE Normal file
View File

@ -0,0 +1,13 @@
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2004 Whomst Ever
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.

37
README.md Normal file
View File

@ -0,0 +1,37 @@
# Route
Minimal PHP Router
# Installation
## Composer
Composer needs to know where to locate the package. Let's add the repository to your project by declaring it in the `composer.json` file.
```JSON
{
"repositories": [
{
"type": "vcs",
"url": "https://git.willy.club/WillySoft/Route"
}
],
"require": {
"willysoft/route": "dev-master"
}
}
```
Fetch the package by running
composer install
# Usage
When using a production web server such as Nginx you will have to tell it to rewrite requests that don't point to a local file, such as they can be forwarded to your front controller which in this case is `public/index.php`.
With PHP already configured, add this to the server block of your configuration to make requests that don't match a file on your server to be sent to your front controller and begin routing.
location / {
try_files $uri $uri/ /index.php?$query_string;
}
See `example.php` and add it to your `public/index.php` file. It will act as the front controller.

88
Route.php Normal file
View File

@ -0,0 +1,88 @@
<?php
namespace WillySoft;
abstract class Route
{
static $prefix = '';
static $groups = [[]];
static function match(string $methods, string $uri, callable $callback)
{
if (!in_array(
$_SERVER['REQUEST_METHOD'],
array_map(strtoupper(...), explode('|', $methods))
)) return;
$request_uri_parts = explode('/', urldecode(
strtok($_SERVER['REQUEST_URI'], '?')
));
$uri_parts = explode('/', self::$prefix . $uri);
$callback_args = [];
for ($i = 0; $i < count($uri_parts); $i++) {
if ($uri_parts[$i] === '')
continue;
if ($uri_parts[$i][0] !== '$')
continue;
if (!isset($request_uri_parts[$i]))
return;
if (
$uri_parts[$i][-1] !== '?'
&& $request_uri_parts[$i] === ''
) return;
if ($request_uri_parts[$i] !== '')
array_push($callback_args, $request_uri_parts[$i]);
$request_uri_parts[$i] = $uri_parts[$i];
}
if (
implode('/', $uri_parts)
!== implode('/', $request_uri_parts)
) return;
foreach (self::$groups as $middlewares) {
foreach ($middlewares as $middleware) {
$middleware();
}
}
$callback(...$callback_args);
die();
}
static function get(string $uri, callable $callback)
{self::match('get', $uri, $callback);}
static function post(string $uri, callable $callback)
{self::match('post', $uri, $callback);}
static function put(string $uri, callable $callback)
{self::match('put', $uri, $callback);}
static function patch(string $uri, callable $callback)
{self::match('patch', $uri, $callback);}
static function delete(string $uri, callable $callback)
{self::match('delete', $uri, $callback);}
static function options(string $uri, callable $callback)
{self::match('options', $uri, $callback);}
static function form(string $uri, callable $callback)
{self::match('get|post', $uri, $callback);}
static function any(string $uri, callable $callback)
{self::match('get|post|put|patch|delete|options', $uri, $callback);}
static function use(callable $middleware)
{
array_push(
self::$groups[array_key_last(self::$groups)],
$middleware
);
}
static function group(string $prefix = '', ?callable $callback = null)
{
if (!str_starts_with(
$_SERVER['REQUEST_URI'],
self::$prefix . $prefix
)) return;
self::$prefix = self::$prefix . $prefix;
array_push(self::$groups, []);
$callback();
array_pop(self::$groups);
self::$prefix = rtrim(self::$prefix, $prefix);
}
}

21
composer.json Normal file
View File

@ -0,0 +1,21 @@
{
"name": "willysoft/route",
"description": "Minimal PHP Router",
"type": "library",
"require": {
"php": ">=8.1.0"
},
"license": "MIT",
"authors": [
{
"name": "noreply",
"email": "noreply@willy.club"
}
],
"minimum-stability": "dev",
"autoload": {
"psr-4": {
"WillySoft\\": "./"
}
}
}

64
example.php Normal file
View File

@ -0,0 +1,64 @@
<?php
use WillySoft\Route as App;
require __DIR__ . '/../vendor/autoload.php';
// middlewares provide a convenient mechanism for inspecting and
// filtering requests. you can imagine them as a series of "layers"
// that requests must pass through before they hit your application.
// a layer can be used for auth, rate limiting or anything really
App::use(
fn() => print('<p>Hello all routes!</p>'));
// there are shorthands for methods you would expect such as
// get|post|put|patch|delete|options
App::get('/',
fn() => print('homepage'));
// form is a shorthand that accepts GET and POST methods
App::form('/submit',
fn() => print('i match on GET and POST methods'));
// any is a shorthand that does what you would expect
App::any('/example',
fn() => print('i match on any method'));
// if not satisfied you can use the match function which takes a
// string of methods separated by the pipe symbol
App::match('get|post|put', '/match',
fn() => print('i match on any method you like'));
// optional route parameters
App::get('/echo/$text?',
fn($text = 'You sent nothing') => print($text));
// required route parameters
App::get('/echo_must_supply_text/$text',
fn($text) => print($text));
// group together routes and middlewares. a prefix can be added to
// prefix each route in the group with a given URI. the group will
// be skipped if the request URI does not begin with the one supplied.
// middlewares defined in here will only affect routes matched from
// within or any child groups
App::group('/test', function() {
App::use(
fn() => print('<p>Hello all routes matched within this or any child groups!</p>'));
// this will be matched as /test/
App::get('/',
fn() => print('Testing 123'));
// you may also define a group without a prefix
App::group(callback: function() {
App::get('/test',
fn() => print('Testing 456'));
});
});
// finally, since no route was matched, show a 404 page
http_response_code(404);
?>
<h1>404 not found</h1>
<p>Sorry, the page you requested could not be found</p>