ellipse / stack
Psr-15 中间件调度器实现
Requires
- php: >=7.0
- ellipse/handlers: ^1.0
- ellipse/type-errors: ^1.0
- psr/http-message: ^1.0
- psr/http-server-handler: ^1.0
- psr/http-server-middleware: ^1.0
Requires (Dev)
- eloquent/phony-kahlan: ^1.0
- kahlan/kahlan: ^4.0
Suggests
- ellipse/dispatcher-callable: Allows to use callables as Psr-15 middleware/request handlers
- ellipse/dispatcher-composable: Allows to compose dispatcher
- ellipse/dispatcher-container: Allows to use Psr-15 middleware/request handler class names using a Psr-11 container
- ellipse/dispatcher-controller: Allows to use controller actions as Psr-15 request handlers using a Psr-11 container
README
此包提供了一个Psr-15调度器实现。
要求 php >= 7.0
安装 composer require ellipse/dispatcher
运行测试 ./vendor/bin/kahlan
使用调度器
此包提供了一个Ellipse\Dispatcher
类,允许通过Psr-15中间件队列(先进先出顺序)处理Psr-7请求,然后再通过Psr-15请求处理器处理,以创建Psr-7响应。
它基本上是一个请求处理器装饰器,将中间件队列包装在请求处理器周围。它的构造函数接受两个参数:
- 一个实现
Psr\Http\Server\RequestHandlerInterface
的请求处理器对象 - 一个包含实现
Psr\Http\Server\MiddlewareInterface
的中间件对象的数组
Dispatcher
本身实现了RequestHandlerInterface
,因此通过其->handle()
方法使用请求产生响应。这也意味着它可以作为另一个Dispatcher
的请求处理器。此外,相同的Dispatcher
可以多次使用来处理所需的请求。
最后,当给定中间件队列的值不是MiddlewareInterface
的实现时,将抛出Ellipse\Dispatcher\Exceptions\MiddlewareTypeException
。可以使用工厂装饰器来解析某些类型的值作为中间件。
<?php namespace App; use Ellipse\Dispatcher; // Create a dispatcher using two middleware and a request handler. $dispatcher = new Dispatcher(new SomeRequestHandler, [ new SomeMiddleware1, new SomeMiddleware2, ]); // Here the request goes through SomeMiddleware1, SomeMiddleware2 and SomeRequestHandler. $response = $dispatcher->handle($request); // It can be used as the request handler of another dispatcher. // Here the request goes through SomeMiddleware3, SomeMiddleware1, SomeMiddleware2 and SomeRequestHandler (new Dispatcher($dispatcher, [new SomeMiddleware3]))->handle($request); // Here a MiddlewareTypeException is thrown because 'something' is not a Psr-15 middleware. new Dispatcher(new SomeRequestHandler, [new SomeMiddleware, 'something']);
Dispatcher
类还有一个->with()
方法,该方法接受一个MiddlewareInterface
作为参数。它返回一个新调度器,其中包含给定中间件包装在当前调度器周围。新中间件将首先由新调度器处理。
<?php namespace App; use Ellipse\Dispatcher; // Create a dispatcher with two middleware. $dispatcher = new Dispatcher(new SomeRequestHandler, [ new SomeMiddleware1, new SomeMiddleware2, ]); // Create a new dispatcher with a new middleware on the top of the middleware queue. $dispatcher = $dispatcher->with(new SomeMiddleware3); // Here the request goes through SomeMiddleware3, SomeMiddleware1, SomeMiddleware2 and SomeRequestHandler. $response = $dispatcher->handle($request); // It allows to create dispatchers from the outside-in if you like. $dispatcher = new Dispatcher(new SomeRequestHandler); $dispatcher = $dispatcher->with(new SomeMiddleware3); $dispatcher = $dispatcher->with(new SomeMiddleware2); $dispatcher = $dispatcher->with(new SomeMiddleware1); // Here the request goes through SomeMiddleware1, SomeMiddleware2, SomeMiddleware3 and SomeRequestHandler. $response = $dispatcher->handle($request);
中间件和请求处理器解析
常见的做法是允许将容器中注册的可调用和类名用作常规中间件/请求处理器。
为此,此包还提供了一个实现Ellipse\DispatcherFactoryInterface
的Ellipse\DispatcherFactory
类,允许产生Dispatcher
实例。它的__invoke()
方法接受任何值作为请求处理器和可选的中间件队列。当给定的请求处理器不是RequestHandlerInterface
的实现时,将抛出Ellipse\Dispatcher\Exceptions\RequestHandlerTypeException
。
<?php namespace App; use Ellipse\DispatcherFactory; // Get a dispatcher factory. $factory = new DispatcherFactory; // Use the factory to create a new Dispatcher. $dispatcher = $factory(new SomeRequestHandler, [new SomeMiddleware]); // Here a RequestHandlerTypeException is thrown because 'something' is not a Psr-15 request handler. $dispatcher = $factory('something', [new SomeMiddleware]); // Here a MiddlewareTypeException is thrown by the Dispatcher class because 'something' is not a Psr-15 middleware. $dispatcher = $factory(new SomeRequestHandler, [new SomeMiddleware, 'something']);
此类本身并不很有用。DispatcherFactory
的目标是将其装饰为其他工厂,在委派调度器创建之前解析给定的值作为Psr-15实现。它是此类工厂装饰器(也称为解析器)的起点,这些装饰器确保当任何值未通过任何装饰器解析为Psr-15实现时,调度器创建失败。
以下是一个使用ellipse/dispatcher-callable包中的Ellipse\Dispatcher\CallableResolver
类进行可调用解析的示例
<?php namespace App; use Ellipse\DispatcherFactory; use Ellipse\Dispatcher\CallableResolver; // Get a decorated dispatcher factory. $factory = new CallableResolver(new DispatcherFactory); // A dispatcher using both callables and Psr-15 implementations can now be created. $middleware = function ($request, $handler) { // This callable behave like a Psr-15 middleware. }; $handler = function ($request) { // This callable behave like a Psr-15 request handler. }; // This works. $response = $factory($handler, [$middleware, new SomeMiddleware])->handle($request);
以下是一些提供常见解析场景解析器的ellipse包
- ellipse/dispatcher-callable 允许使用可调用对象作为 Psr-15 中间件/请求处理器
- ellipse/dispatcher-container 允许使用 Psr-15 中间件/请求处理器类名通过一个 Psr-11 容器
- ellipse/dispatcher-controller 允许使用控制器操作作为 Psr-15 请求处理器,通过一个 Psr-11 容器
以下是一个实现 DispatcherFactoryInterface
的类示例,如果您需要创建一个自定义的,可以参考
<?php namespace App; use Ellipse\Dispatcher; use Ellipse\DispatcherFactoryInterface; class MyResolver implements DispatcherFactoryInterface { private $delegate; public function __construct(DispatcherFactoryInterface $delegate) { $this->delegate = $delegate; } public function __invoke($handler, array $middleware = []): Dispatcher { // Replace the handler with a ResolvedRequestHandler when the request handler should be resolved. $handler = $this->shouldResolveHandler($handler) : new ResolvedRequestHandler($handler) ? $handler; // Replace middleware with a ResolvedMiddleware when a middleware should be resolved. $middleware = array_map(function ($middleware) { return $this->shouldResolveMiddleware($middleware) ? new ResolvedMiddleware($middleware) : $middleware; }, $middleware); // Delegate the dispatcher creation to the decorated factory. return ($this->delegate)($handler, $middleware); } private shouldResolveHandler($handler): bool { // ... } private shouldResolveMiddleware($middleware): bool { // ... } }