rarerloop / router
一个受 Laravel API 启发的强大 PHP 路由器,用于 PSR7 消息
Requires
- php: ^7.3||^8.0
- altorouter/altorouter: ^2.0.2
- laminas/laminas-diactoros: ^2.4
- mindplay/middleman: ^3.0.3
- php-di/invoker: ^2.3.0
- psr/container: ^1.0
- psr/http-message: ^1.0
- psr/http-server-middleware: ^1.0
- spatie/macroable: ^1.0
Requires (Dev)
- mockery/mockery: ^1.4.3
- php-coveralls/php-coveralls: ^2.4
- php-di/php-di: ^6.3.4
- phpunit/phpunit: ^9.5
- squizlabs/php_codesniffer: ^3.6.0
- dev-master
- v6.0.2
- v6.0.1
- v6.0.0
- v5.0.0
- v4.x-dev
- v4.4.1
- v4.4.0
- v4.3.1
- v4.3.0
- v4.2.0
- v4.1.0
- v4.0.0
- v3.2.1
- v3.2.0
- v3.1.0
- v3.0.1
- v3.0.0
- v2.1.0
- v2.0.0
- v1.0.0
- dev-bugfix/route-dots
- dev-resolve-82-issues-in-tests
- dev-add-php81-support
- dev-fix-typo-in-docs
- dev-altorouter-fix
- dev-migrate-to-github-actions
- dev-support-php8
- dev-upgrade-to-laminas
- dev-middleware-resolver
- dev-update-dependencies
- dev-middleware-aliases
This package is auto-updated.
Last update: 2024-09-20 14:36:49 UTC
README
一个基于 AltoRouter 构建,但受 Laravel API 启发的简单 PHP 路由器。
安装
composer require rareloop/router
用法
创建路由
映射
创建路由是通过使用 map
函数完成的
use Rareloop\Router\Router; $router = new Router; // Creates a route that matches the uri `/posts/list` both GET // and POST requests. $router->map(['GET', 'POST'], 'posts/list', function () { return 'Hello World'; });
map()
需要 3 个参数
methods
(数组):匹配请求方法的列表,有效值GET
POST
PUT
PATCH
DELETE
OPTIONS
uri
(字符串):要匹配的 URIaction
(函数|string):要么是一个闭包,要么是一个控制器字符串
路由参数
可以使用 {keyName}
语法在路由上定义参数。当一个匹配包含参数的路由时,将传递一个 RouteParams
对象实例到动作。
$router->map(['GET'], 'posts/{id}', function(RouteParams $params) { return $params->id; });
如果您需要向参数添加约束,可以将正则表达式模式传递到定义的 Route
的 where()
函数
$router->map(['GET'], 'posts/{id}/comments/{commentKey}', function(RouteParams $params) { return $params->id; })->where('id', '[0-9]+')->where('commentKey', '[a-zA-Z]+'); // or $router->map(['GET'], 'posts/{id}/comments/{commentKey}', function(RouteParams $params) { return $params->id; })->where([ 'id', '[0-9]+', 'commentKey', '[a-zA-Z]+', ]);
可选路由参数
有时您的路由参数需要是可选的,在这种情况下,您可以在参数名称后添加一个 ?
$router->map(['GET'], 'posts/{id?}', function(RouteParams $params) { if (isset($params->id)) { // Param provided } else { // Param not provided } });
命名路由
路由可以被命名,以便可以程序化地生成它们的 URL
$router->map(['GET'], 'posts/all', function () {})->name('posts.index'); $url = $router->url('posts.index');
如果路由需要参数,您可以传递一个关联数组作为第二个参数
$router->map(['GET'], 'posts/{id}', function () {})->name('posts.show'); $url = $router->url('posts.show', ['id' => 123]);
如果传递的参数未通过正则表达式约束,将抛出 RouteParamFailedConstraintException
。
HTTP 动词快捷方式
通常您只需要为路由允许一个 HTTP 动词,对于这些情况,可以使用以下快捷方式
$router->get('test/route', function () {}); $router->post('test/route', function () {}); $router->put('test/route', function () {}); $router->patch('test/route', function () {}); $router->delete('test/route', function () {}); $router->options('test/route', function () {});
设置基本路径
路由器假设您正在处理域的路由。如果这不是这种情况,您可以设置基本路径
$router->setBasePath('base/path'); $router->map(['GET'], 'route/uri', function () {}); // `/base/path/route/uri`
控制器
如果您希望使用一个类来将相关的路由操作分组在一起,您可以将控制器字符串传递到 map()
而不是闭包。字符串的格式为 {类名}@{方法名}
。使用类的完整命名空间和类名非常重要。
示例
// TestController.php namespace \MyNamespace; class TestController { public function testMethod() { return 'Hello World'; } } // routes.php $router->map(['GET'], 'route/uri', '\MyNamespace\TestController@testMethod');
创建组
通常,将类似的路由放在一个共同的名称前缀后面。这可以通过路由组实现
$router->group('prefix', function ($group) { $group->map(['GET'], 'route1', function () {}); // `/prefix/route1` $group->map(['GET'], 'route2', function () {}); // `/prefix/route2§` });
中间件
PSR-15/7 中间件可以添加到路由和组。
向路由添加中间件
在最简单的情况下,通过传递一个对象到 middleware()
函数来向路由添加中间件
$middleware = new AddHeaderMiddleware('X-Key1', 'abc'); $router->get('route/uri', '\MyNamespace\TestController@testMethod')->middleware($middleware);
可以通过向 middleware()
函数传递更多参数来添加多个中间件
$header = new AddHeaderMiddleware('X-Key1', 'abc'); $auth = new AuthMiddleware(); $router->get('route/uri', '\MyNamespace\TestController@testMethod')->middleware($header, $auth);
或者,您也可以传递一个中间件数组
$header = new AddHeaderMiddleware('X-Key1', 'abc'); $auth = new AuthMiddleware(); $router->get('route/uri', '\MyNamespace\TestController@testMethod')->middleware([$header, $auth]);
向组添加中间件
您还可以向组添加中间件。为此,您需要将一个数组作为 group()
函数的第一个参数传递,而不是一个字符串。
$header = new AddHeaderMiddleware('X-Key1', 'abc'); $router->group(['prefix' => 'my-prefix', 'middleware' => $header]), function ($group) { $group->map(['GET'], 'route1', function () {}); // `/my-prefix/route1` $group->map(['GET'], 'route2', function () {}); // `/my-prefix/route2§` });
如果您需要多个中间件,您也可以传递一个中间件数组
$header = new AddHeaderMiddleware('X-Key1', 'abc'); $auth = new AuthMiddleware(); $router->group(['prefix' => 'my-prefix', 'middleware' => [$header, $auth]]), function ($group) { $group->map(['GET'], 'route1', function () {}); // `/my-prefix/route1` $group->map(['GET'], 'route2', function () {}); // `/my-prefix/route2§` });
在控制器上定义中间件
您还可以在控制器类上应用中间件。为了做到这一点,您的控制器必须扩展 Rareloop\Router\Controller
基类。
通过在控制器中的 __constructor()
中调用 middleware()
函数来添加中间件。
use Rareloop\Router\Controller; class MyController extends Controller { public function __construct() { // Add one at a time $this->middleware(new AddHeaderMiddleware('X-Key1', 'abc')); $this->middleware(new AuthMiddleware()); // Add multiple with one method call $this->middleware([ new AddHeaderMiddleware('X-Key1', 'abc', new AuthMiddleware(), ]); } }
默认情况下,通过控制器添加的所有中间件将影响该类上的所有方法。要限制中间件应用于哪些方法,您可以使用 only()
和 except()
。
use Rareloop\Router\Controller; class MyController extends Controller { public function __construct() { // Only apply to `send()` method $this->middleware(new AddHeaderMiddleware('X-Key1', 'abc'))->only('send'); // Apply to all methods except `show()` method $this->middleware(new AuthMiddleware())->except('show'); // Multiple methods can be provided in an array to both methods $this->middleware(new AuthMiddleware())->except(['send', 'show']); } }
将路由匹配到请求
一旦您定义了路由,就可以使用 match()
函数尝试将当前请求与它们进行匹配。 match()
接受一个 Symfony 的 Request
实例,并返回一个 Symfony 的 Response
实例
$request = Request::createFromGlobals(); $response = $router->match($request); $response->send();
返回值
如果您从闭包中返回一个 Response
实例,它将被原样发送。但是,如果您返回其他内容,它将被包装在一个包含您返回值的 Response
实例中。
响应对象
如果您从闭包中返回一个实现了 Responsable
接口的对象,它将自动为您调用 toResponse()
对象。
class MyObject implements Responsable { public function toResponse(RequestInterface $request) : ResponseInterface { return new TextResponse('Hello World!'); } } $router->get('test/route', function () { return new MyObject(); });
404
如果没有路由匹配请求,将返回一个状态码设置为 404
的 Response
对象;
访问当前路由
可以通过调用以下方法来检索当前匹配的 Route
$route = $router->currentRoute();
如果没有路由匹配或尚未调用 match()
,将返回 null
。
您还可以通过调用以下方法来访问当前匹配的 Route
的名称
$name = $router->currentRouteName();
如果没有路由匹配或尚未调用 match()
,或者匹配的路由没有名称,将返回 null
。
与依赖注入容器一起使用
路由器也可以与您选择的 PSR-11 兼容容器一起使用。这允许您在路由闭包或控制器方法中为依赖项添加类型提示。
要使用容器,只需将其作为参数传递给路由器的构造函数
use MyNamespace\Container; use Rareloop\Router\Router; $container = new Container(); $router = new Router($container);
之后,您的路由闭包和控制器方法将自动添加类型提示
$container = new Container(); $testServiceInstance = new TestService(); $container->set(TestService::class, $testServiceInstance); $router = new Router($container); $router->get('/my/route', function (TestService $service) { // $service is now the same object as $testServiceInstance });