icanboogie / routing
请求路由
Requires
- php: >=7.2
- ext-json: *
- icanboogie/http: ^4.0
Requires (Dev)
- phpunit/phpunit: ^8.5
README
icanboogie/routing 包处理原生PHP中的URL重写。请求被映射到路由,路由再映射到响应器。如果处理成功,则返回响应。事件在过程中发出,以允许监听器修改请求或响应,或从失败中恢复。
以下示例是请求处理的概述。路由组件是响应器提供者堆栈的一部分。
<?php namespace ICanBoogie\HTTP; /* @var ResponderProvider $responder_provider */ // The request is usually created from the $_SERVER super global. $request = Request::from($_SERVER); // The Responder Provider matches a request with a Responder $responder = $responder_provider->responder_for_request($request); // The Responder responds to the request with a Response, it might also throw an exception. $response = $responder->respond($request); // The response is sent to the client. $response();
安装
composer require icanboogie/routing
路由
路由用 Route 实例表示。创建实例需要两个参数:pattern
和 action
。 pattern
是匹配或生成URL的模式。action
是一个用于匹配响应器的操作标识符。
路由模式
模式用于匹配URL与路由。可以使用占位符将多个URL匹配到单个路由并提取其参数。有三种类型的占位符可用
-
宽松占位符:仅指定参数的名称,它匹配任何直到下一个部分的内容。例如:
/articles/:id/edit
。 -
约束占位符:使用正则表达式匹配参数值。例如:
/articles/<id:\d+>/edit
,其中<id:\d+>
是id
参数的占位符,其值必须匹配/^\d+$/
。 -
匿名约束占位符:与约束占位符相同,但参数没有名称,而是一个索引,例如:
/articles/<\d+>/edit
,其中<\d+>
是一个占位符,其索引为0。
此外,joker字符 *
可以在模式的末尾使用,它匹配任何内容。例如:/articles/123*
匹配 /articles/123
和 /articles/123456
。
最后,约束正则表达式扩展如下
{:sha1:}
:匹配 SHA-1 哈希。例如:/files/<hash:{:sha1:}>
。{:uuid:}
:匹配 UUID(通用唯一标识符)。例如:/articles/<uuid:{:uuid:}>/edit
。
您可以将它们组合使用
/blog/:year-:month-:slug
/blog/<year:\d{4}>-<month:\d{2}>-:slug
/images/<uuid:{:uuid:}>/<size:\d+x|x\d+|\d+x\d+>*
路由提供者
路由提供者用于找到与谓词匹配的路由。简单的路由提供者通常被更复杂的提供者装饰,以提高性能。
以下是一个路由提供者使用的概述,详细信息请参阅 路由提供者文档。
<?php namespace ICanBoogie\Routing; use ICanBoogie\HTTP\RequestMethod; use ICanBoogie\Routing\RouteProvider\ByAction; use ICanBoogie\Routing\RouteProvider\ByUri; /* @var RouteProvider $routes */ $routes->route_for_predicate(new ByAction('articles:show')); $routes->route_for_predicate(new ByUri('/articles/123', RequestMethod::METHOD_GET)); $routes->route_for_predicate(fn(Route $route) => $route->action === 'articles:show');
响应用户请求
如果路由匹配请求URI和方法,则可以将请求调度到匹配的响应器。
<?php use ICanBoogie\HTTP\Request; use ICanBoogie\HTTP\RequestMethod; use ICanBoogie\HTTP\Responder; use ICanBoogie\Routing\RouteProvider; $routes = new RouteProvider\Immutable([ new Route('/articles/<id:\d+>', 'articles:delete', RequestMethod::METHOD_DELETE) ]); $request = Request::from([ Request::OPTION_URI => "/articles/123", Request::OPTION_METHOD => RequestMethod::METHOD_DELETE, ]); /* @var Responder $responder */ $response = $responder->respond($request);
控制器
之前的示例展示了如何使用闭包来处理路由。在开始构建应用程序时,闭包是完全可以接受的,但随着应用程序的增长,你可能希望使用控制器类来更好地组织你的应用程序。你可以将每个路由映射到其控制器类,或者使用ActionTrait来将相关的HTTP请求处理逻辑组合到单个控制器中。
控制器响应
当被调用时,控制器应该返回一个结果,或者在无法处理请求时返回null
。`action()`方法的返回结果由`__invoke()`方法处理:如果结果是Response实例,则直接返回;如果控制器附加的Response实例已初始化(例如通过`$this->response`属性),则使用结果作为响应体;否则,直接返回结果。
在执行动作之前
类Controller\BeforeActionEvent的事件`ICanBoogie\Routing\Controller::action:before`在调用`action()`方法之前触发。事件钩子可以使用此事件提供响应,从而取消动作。事件钩子也可以使用此事件在执行动作之前更改控制器。
在执行动作之后
类Controller\ActionEvent的事件`ICanBoogie\Routing\Controller::action:after`在调用`action()`方法之后触发。事件钩子可以使用此事件更改方法的结果。
基本控制器
基本控制器从Controller扩展,必须实现`action()`方法。
注意:`action()`方法在控制器内部由`__invoke()`方法调用,应定义为`protected`。`__invoke()`方法是最终的,因此不能被重写。
<?php namespace App\Modules\Articles\Routing; use ICanBoogie\HTTP\Request; use ICanBoogie\Routing\Controller; class DeleteController extends Controller { protected function action(Request $request) { // Your code goes here, and should return a string or a Response instance } }
尽管任何实现`__invoke()`的类都适合作为控制器,但推荐扩展Controller,因为这使访问应用程序功能变得更加容易。此外,你可能还会从附加到Controller类的原型方法和事件钩子中受益,例如由icanboogie/view包添加的`view`属性。
Controller类提供的以下属性
name
:控制器的名称,从其类名中提取,例如"articles_delete"。request
:正在分发中的请求。route
:正在分发的路由。
动作控制器
以下是一个动作控制器的示例,详细信息请参阅动作控制器文档。
<?php use ICanBoogie\Routing\ControllerAbstract; use ICanBoogie\Routing\Controller\ActionTrait; final class ArticleController extends ControllerAbstract { use ActionTrait; private function list(): string { // … } private function show(): string { // … } }
异常
该软件包定义的异常实现了ICanBoogie\Routing\Exception
接口,因此易于识别
<?php try { // … } catch (\ICanBoogie\Routing\Exception $e) { // a routing exception } catch (\Exception $e) { // another type of exception }
定义了以下异常
- ActionNotDefined:当未定义动作时抛出,例如当使用ActionTrait的控制器具有空的`action`属性时。
- InvalidPattern:在尝试定义没有模式的路由时抛出。
持续集成
该项目由 GitHub actions 进行持续测试。
行为准则
本项目遵循 贡献者行为准则。通过参与本项目及其社区,您应遵守此准则。
贡献
请参阅 CONTRIBUTING 了解详细信息。
许可证
icanboogie/routing 采用 BSD-3-Clause 许可。