ellipse/stack

此包已被放弃,不再维护。未建议替代包。

Psr-15 中间件调度器实现

1.6.1 2018-03-19 15:30 UTC

This package is not auto-updated.

Last update: 2022-02-01 13:08:49 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。可以使用工厂装饰器来解析某些类型的值作为中间件。

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

以下是一些提供常见解析场景解析器的ellipse包

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