stratify / router
Requires
- php: >=7.1
- aura/router: ^3.0
- php-di/invoker: ^2.0
- psr/container: ^1.0
- psr/http-message: ^1.0
- stratify/http: ~0.5.0
Requires (Dev)
- phpunit/phpunit: ^6.0
README
作为 PSR-7 中间件实现的路由器。
本软件包提供了 3 个路由器
- 一个用于 Web 应用程序的“经典”路由器
- 一个用于构建 REST API 的 REST 路由器
- 一个基于 URL 前缀将路由转发到子中间件的“前缀”路由器
一切都是中间件
每个路由器都是一个中间件,这意味着可以在中间件堆栈中多次使用它。这也意味着,如果一个路由器没有匹配到请求的路由,这不是错误:它将简单地调用 $next
中间件。
此外,控制器(即路由处理器)也是中间件。路由器只是将请求的流程路由到中间件的子分支。这允许删除“路由中间件”的具体概念。
以下是一个示例,展示了如何在单个应用程序中使用多个路由器,以及如何在路由中使用中间件
use Stratify\Http\Middleware\MiddlewarePipe; use Stratify\Router\PrefixRouter; use Stratify\Router\Router; $app = new MiddlewarePipe([ new ErrorHandlerMiddleware(), // a middleware that applies to the whole stack new PrefixRouter([ // The blog has its own router '/blog/' => new Router([ '/blog/' => new HomeController(), '/blog/{article}' => new ArticleController(), ]), // The API has its own router with its own middlewares (authentication for example) '/api/' => new MiddlewarePipe([ new HttpBasicAuthMiddleware(), // authentication only for the API new Router([ '/api/articles' => new ArticleController(), '/api/users' => new UserController(), ]), ]), ]), ]);
请注意,这个示例过于简化。利用依赖注入、控制器/中间件的懒加载实例化以及更简单的应用程序配置 API 是完全可能的;这正是 Stratify 框架 在路由器之上提供的。
安装
composer require stratify/router
经典路由器
这个“经典”路由器与其他 PHP 路由器非常相似。它是基于 Aura.Router 构建的。
路由器接收一个从 URL 到可调用的映射,例如
$router = new Router([ '/' => function (...) { ... }, ]);
默认情况下,只有 HTTP GET
方法会被允许。
可以在路由路径中使用占位符,并从请求属性中获取或注入为参数
'/article/{id}' => function ($id) { ... }, '/category/{id}' => function (ServerRequestInterface $request) { $id = $request->getAttribute('id'); ... },
可以使用 route()
助手更详细地配置路由
-
占位符格式(使用正则表达式)
use function \Stratify\Router\route; $router = new Router([ '/{id}' => route(function () { … }) ->pattern('id', '\d+') // the placeholder must be a number ]);
-
可选占位符
'/export.{format}' => route(/* callable */) ->optional('format', 'json'),
-
接受的 HTTP 方法
'/subscribe' => route(/* callable */) ->method('POST'),
HTTP 资源
可以使用 resource()
助手为每个 HTTP 方法定义单独的处理程序
use function \Stratify\Router\resource; $router = new Router([ '/' => resource([ 'get' => function () { … }, 'post' => function () { … }, ]), ]);
但是,如果您计划使用所有 HTTP 方法,您可能希望使用 RestRouter
。
控制器
控制器,也称为“路由处理器”,可以是任何 PHP 可调用(闭包、对象方法、可调用对象等)。
可调用函数可以决定它将接受哪些参数。路由器将根据可调用函数的参数检测要提供的内容。参数可以是
- PSR-7 请求:
ServerRequestInterface $request
;在这种情况下,参数 必须命名为$request
- 任何请求属性,包括
- 路由占位符:
/order/{orderId}
=> 您可以有一个$orderId
参数(参数名称必须与路由占位符名称相同) - 或任何由前面的中间件定义的属性(例如,如果认证中间件定义了一个
user
属性,您可以有一个$user
参数)
- 路由占位符:
- 要调用的下一个可调用函数(
$next
参数),见下文
由于控制器/路由处理器 是 中间件,它也可以有中间件签名
function (ServerRequestInterface $request, callable $next) { }
控制器响应
控制器,就像中间件一样,预期返回 PSR-7 响应对象。
然而,为了便于开发,它们也可以返回字符串:这些字符串将被自动转换为 200
HTML 响应。
function () { return 'Hello world!'; } // Same as function () { return new HtmlResponse('Hello world!'); }
REST 路由器
REST 路由器的行为与经典路由器完全相同(对于控制器,适用相同的规则),只是它更容易为 HTTP 资源注册处理程序。
$router = new RestRouter([ '/articles' => new ArticleController, ]);
这与经典路由器的此映射等效
$router = new RestRouter([ '/articles' => resource([ 'get' => [new ArticleController, 'index'], 'post' => [new ArticleController, 'post'], ]), '/articles/{id}' => resource([ 'get' => [new ArticleController, 'get'], 'put' => [new ArticleController, 'put'], 'delete' => [new ArticleController, 'delete'], ]), ]);
以下是一个 REST 控制器的示例
class ArticleController { public function index() { return new HtmlResponse('Index'); } public function post() { return new HtmlResponse('POST'); } public function get(ServerRequestInterface $request) { return new HtmlResponse('GET '.$request->getAttribute('id')); } public function put(ServerRequestInterface $request) { return new HtmlResponse('PUT '.$request->getAttribute('id')); } public function delete(ServerRequestInterface $request) { return new HtmlResponse('DELETE '.$request->getAttribute('id')); } }
前缀路由器
PrefixRouter
是一个非常简单且非常快的路由器,它根据 URL 前缀进行路由。
$router = new PrefixRouter([ '/api/' => /* API middleware stack */, '/admin/' => /* Admin middleware stack */, '/' => /* Public website middleware stack */, ]);
首先匹配到的前缀会被使用。每个路由处理器都必须是中间件,即一个签名符合的调用对象
function (ServerRequestInterface $request, callable $next) : ResponseInterface { }
前缀路由器对于分离大型应用中不需要相同中间件的几个部分非常有用,例如
- 所有“admin”部分需要认证,但在公共网站上不需要认证
- 公共网站需要缓存,但在后端不需要缓存
- API 需要内容协商和令牌认证,但应用的其他部分不需要
- 等等。