ginger-tek / routy
一个简单、健壮的PHP路由器,用于快速开发应用程序和API
Requires
- php: >=8.1.0
README
Routy
一个简单、健壮的PHP路由器,用于快速开发应用程序和API
入门
Composer
composer require ginger-tek/routy
require 'vendor/autoload.php'; use GingerTek\Routy; $app = new Routy();
启动示例
每个路由的处理程序可以是任何可调用的类型,例如普通函数、箭头函数、闭包变量或静态类方法。
$app = new Routy(); // Standard Function $app->get('/things', function (Routy $app) { $app->sendData('Hello!'); }); // Arrow Function $app->get('/', fn (Routy $app) => $app->sendData('Hello!');); // Closure $handler = function (Routy $app) { $app->sendData('Hello!'); }; $app->get('/closure', $handler); // Static Class Method class ProductsController { static function getAll($app) { $app->sendData('Hello!'); } } $app->get('/products', \ProductsController::getAll(...));
配置
可以将可选配置的关联数组传递给构造函数。
base
用于设置运行时子目录的全局基本URIlayout
用于设置用于render()
响应方法的默认布局模板文件
$app = new Routy([ 'base' => '/api', 'layout' => 'path/to/layout.php' ])
特性
方法包装器
使用方法包装器进行路由GET、POST、PUT、PATCH或DELETE方法请求。还有一个匹配所有标准HTTP方法(包括HEAD和OPTIONS)的通配符包装器。
$app->get('/products', ...); // HTTP GET $app->post('/products/:id', ...); // HTTP POST $app->put('/products', ...); // HTTP PUT $app->patch('/products/:id', ...); // HTTP PATCH $app->delete('/products/:id', ...); // HTTP DELETE $app->any('/products/:id', ...); // HTTP GET, POST, PUT, PATCH, DELETE, HEAD, and OPTIONS
使用 *
作为路由参数匹配任何路由。
$app->get('*', ...); // HTTP GET for all routes $app->any('*', ...); // Any standard HTTP method for all routes
自定义路由
您还可以直接使用 route()
方法,这是常用包装器下面的方法,以创建更具体的匹配路由条件。
$app->route('GET|POST', '/form', ...); // HTTP GET and POST for the /form route $app->route('GET|POST|PUT', '/products', ...); // HTTP GET, POST and PUT for the /products route
动态路由
要定义动态路由参数,请使用 :param
语法,并通过 $app
上下文上的 params
对象访问它们。
$app->get('/products/:id', function(Routy $app) { $id = $app->params->id; // ... });
中间件
URI字符串参数设置之后的所有参数都被视为中间件函数,包括路由处理程序,因此可以定义所需数量。
使用本地 $_REQUEST
和 $_SESSION
全局变量在中间件/处理程序之间共享数据。
function authenticate(Routy $app) { if(!($token = @$app->getHeaders()['authorization'])) $app->end(401); $_REQUEST['user'] = parseToken($token); } $app->get('/products', authenticate(...), function (Routy $app) { $userId = $_REQUEST['user']->id; $items = getProductsByUser($userId); $app->sendJson($items); });
路由分组
您可以使用 group()
方法定义路由分组。
$app = new Routy(); $app->group('/products', function (Routy $app) { $app->post('/', ...); $app->get('/', ...); $app->get('/:id', ...); $app->patch('/:id', ...); });
您还可以向嵌套路由添加中间件
$app->group('/products', authenticate(...), function (Routy $app) { $app->get('/', ...); });
后备路由
后备路由用于返回自定义的404响应,或在其他返回之前执行其他逻辑。
要设置后备路由,请使用 notFound()
方法设置一个处理函数,该函数将具有已设置HTTP 404响应头的响应。
后备路由的作用域是它们定义的地方,并且只有在它们匹配传入URI的父路径时才会被访问。
$app = new Routy(); $app->group('/products', function (Routy $app) { $app->get('/', fn (Routy $app) => $app->sendJson([])); // GET /products/asdf will end up here $app->notFound(function (Routy $app) { ... }); }); // GET /asdf will end up here $app->notFound(function (Routy $app) { ... });
服务静态文件(SPA)
要从与SPA前端相同的应用程序直接从基本URI服务静态文件,请在所有其他路由定义之后使用 serveStatic()
方法 之后。
此功能通常由您的实际Web服务器(Apache/nginx/caddy)执行,因此在生产场景中使用时请谨慎。由于此功能使您的应用程序能够处理文件服务,您的应用程序必须作为文件服务的路由器运行,即 php -S localhost:8000 router.php
。
$app = new Routy(); $app->group('/api', ApiController::index(...)); $app->serveStatic('public');
如果请求的文件未找到,将提供路径 + index.html
。如果没有 index.html
文件,将返回失败路径。
## Request Properties
You can access the incoming HTTP method and URI via the `uri`, `method`, and `params`, and `query` properties on the `$app` instance.
```php
$app->get('/', function (Routy $app) {
$app->uri;
$app->method;
$app->params;
$app->query;
});
请求辅助方法
有一些辅助方法用于处理传入的请求数据。
getBody()
用于检索传入的有效负载数据。JSON数据将自动解码,表单URL编码数据将作为标准对象访问。
$app->get('/products', function (Routy $app) { $body = $app->getBody(); // JSON // { "someProperty": "asdf" } $body->someProperty; $body->username; // From: <input name="username"> });
getHeaders()
用于检索传入的HTTP头,以关联数组的形式,每个头键都是自动小写化的,以便标准化。
$app->get('/products', function (Routy $app) { $headers = $app->getHeaders(); $headers->authorization; // Bearer eyhdgs9d8fg9s7d87f... });
getFiles()
用于从multipart/form-data请求检索上传的文件。对于多文件上传返回对象数组。要为单文件上传返回第一个对象,请将第二个参数设置为 true
。
<form method="POST" action="/upload" enctype="multipart/form-data"> <input type="file" name="multi[]" multiple required> <input type="file" name="single" required> <button type="submit">Submit</button> </form>
$app->post('/upload', function (Routy $app) { $multipleFiles = $app->getFiles('multi'); // object array $singleFile = $app->getFiles('single', true); // object });
响应辅助方法
处理响应有很多辅助方法。
sendJson()
用于返回JSON字符串数据
$app->sendJson(['prop' => 'value']); // { "prop": "value" } $app->sendJson([1, 2, ['three' => 4], 5]); // [1, 2, { "three: 4 }, 5]
sendData()
用于返回字符串数据或文件的原始内容
$app->sendData('<h1>Raw HTML</h1>'); $app->sendData('path/to/file.html');
redirect()
用于发送临时或永久重定向到新的URL
$app->redirect('/go/here'); // HTTP 302 $app->redirect('/new/permanent/location', true); // HTTP 301
render()
用于渲染PHP视图文件,使用标准的PHP包含和变量作用域提取进行MCV建模
您可以通过构造函数配置来设置默认布局
$app = new Routy(['layout' => 'path/to/layout.php']); ... $app->render('views/home.php'); $app->render('views/about.php')
您还可以通过将layout
选项设置为另一个路径来覆盖默认布局
$app = new Routy(['layout' => 'path/to/layout1.php']); ... $app->render('path/to/view.php', ['layout' => 'path/to/layout2.php']);
或者,您可以通过将layout
选项设置为false
来不使用布局
$app = new Routy(['layout' => 'path/to/layout.php']); ... $app->render('path/to/view.php', ['layout' => false]);
您也可以完全不指定布局,直接渲染文件
$app = new Routy(); ... $app->render('path/to/view.php');
最后,将model
选项设置为传递数据模型,以便在视图文件中将数据暴露给模板上下文
$app->render('path/to/view.php', [ 'model' => [ 'someProperty' => 'some data' ] ]); // view.php <div><?= $model->someProperty ?></div>
status()
用于设置HTTP状态码。这可以用于方法链到其他响应方法
$app->post('/products', function (Routy $app) { $app->status(400)->sendJson(['error' => 'Bad payload']); // or $app->status(201)->sendData('Successfully created!'); });
end()
用于立即返回,并可选地设置HTTP状态码
$app->end(); // Success $app->end(401); // Unauthorized $app->end(404); // Not Found