椭圆/分发器

该包已被弃用且不再维护。作者建议使用 quanta/http-dispatcher 包。

Psr-15 中间件分发器实现

1.6.1 2018-03-19 15:30 UTC

This package is auto-updated.

Last update: 2019-12-20 15:38:32 UTC


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。可以使用 Factory decorators 来解析某些类型的值作为中间件。

<?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\DispatcherFactoryInterfaceEllipse\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);

以下是提供常见解析场景解析器的某些椭圆包

以下是一个实现 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
    {
        // ...
    }
}