bitexpert/adroit

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

基于 ADR (Action Domain Responder) 规范的 PSR-7 中间件。

v0.7.0 2017-02-15 10:38 UTC

README

此包提供了一个兼容 PSR-7ADR 中间件。

Build Status Coverage Status

安装

安装 bitexpert/adroit 的首选方式是通过 Composer。只需将 bitexpert/adroit 添加为依赖项

composer.phar require bitexpert/adroit

使用方法

为了配置 \bitExpert\Adroit\AdroitMiddleware 中间件,你需要提供一个 \bitExpert\Adroit\Action\Resolver\ActionResolver 数组,一个 \bitExpert\Adroit\Responder\Resolver\ResponderResolver 数组以及一个动作请求属性,告诉 adroit 在哪里查找动作标识符。

动作解析器

如名称所示,动作解析器负责从所谓的动作令牌中解析动作类实例。动作令牌基本上用于识别一个路由。Adroit 包含一个默认的 动作解析器 实现,它使用任何兼容 container-interop 的 DI 容器作为后端。

当然,你可以使用 (\bitExpert\Adroit\Action\ActionResolver) 接口实现自己的动作解析器。

/** @var \Interop\Container\ContainerInterface $container */
$actionResolver = new \bitExpert\Adroit\Action\Resolver\ContainerActionResolver($container);

响应解析器

类似于动作解析器,响应解析器负责从 DomainPayload 实例中定义的 $type 解析响应类实例。Adroit 包含一个默认的 响应解析器 实现,它使用任何兼容 container-interop 的 DI 容器作为后端。

当然,你可以使用 响应解析器 接口实现自己的响应解析器。

/** @var \Interop\Container\ContainerInterface $container */
$responderResolver = new \bitExpert\Adroit\Responder\Resolver\ContainerAwareResponderResolver($container);

(域)有效负载

你可以通过实现 \bitExpert\Adroit\Domain\Payload 接口来定义自己的有效负载类。这使你能够根据需要自由定义有效负载。以下示例实现将在文档中如下使用

<?php
namespace Acme\Domain;
use bitExpert\Adroit\Domain\Payload;

class CustomPayload implements Payload
{
    protected $type;
    protected $data;

    public function __construct($type, array $data = [])
    {
        $this->type = $type;
        $this->data = $data;
    }

    public function getType()
    {
        return $this->type;
    }

    public fuction getValue($name)
    {
        return isset($this->data[$name]) ? $this->data[$name] : null;
    }
}

动作

如果你想要实现自己的动作逻辑(谁不想呢?),你可以使用任何遵循 Action 接口签名的可调用对象,或者创建自己的动作类并实现该接口。

动作类可以返回实现 Payload 接口的对象,或者实现 \Psr\Http\Message\ResponseInterface 接口的 PSR-7 响应对象。默认情况下,你应该旨在返回一个 Payload 对象。PSR-7 响应可能在处理文件下载时很有用,在这种情况下,你很可能不想在动作类中读取文件,将内容推送到响应器,然后再将其写入响应消息体。

<?php 
use Acme\Domain\CustomPayload;
use bitExpert\Adroit\Action\Action;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

class HelloWorldAction implements Action
{
    /**
     * @inheritdoc
     */
    protected function __invoke(ServerRequestInterface $request, ResponseInterface $response)
    {
        return new CustomPayload('hello', ['name' => 'World']);
    }
}

响应者

响应者必须返回一个PSR-7响应对象。响应者不强制实现响应者接口,因此您也可以使用闭包,但推荐实现该接口。

<?php 
namespace Acme\Responder\HelloResponder;

use bitExpert\Adroit\Responder\Responder;
use bitExpert\Adroit\Domain\Payload;
use Psr\Http\Message\ResponseInterface;

class HelloResponder implements Responder
{
    /**
     * @inheritdoc
     */
    public function __invoke(Payload $domainPayload, ResponseInterface $response)
    {
        $response->getBody()->rewind();
        $response->getBody()->write('Hello ' . $domainPayload->getValue('name'));
        
        return $response->withStatus(200)
    }
}

使用方法

由于Adroit提供了一套方便的中间件来实现ADR,您只需配置您的ActionResolver和ResponderResolver即可。以下示例中,我们使用了bitexpert/specialist的ArrayContainer,这些通过一个将操作标识符与操作以及域有效负载类型与适当的响应者之间的映射数组进行配置。

<?php
use bitExpert\Specialist\Container\ArrayContainer;

$container = new ArrayContainer([
    'helloAction' => function (ServerRequestInterface $request, ResponseInterface $response) {
        return new CustomPayload('hello', [
            'name' => 'World'
        ]);
    },
    'hello' => function (Payload $domainPayload, ResponseInterface $response) {
        $response->getBody()->rewind();
        $response->getBody()->write('Hello ' . $domainPayload->getValue('name'));
        return $response;
    };    
]);

// create the action resolver
$actionResolver = new ContainerActionResolver($container);


// create the responder resolver
$responderResolver = new ContainerResponderResolver($container);

// Provide the request attribute where the routing result identifier is kept
// and your resolvers
$adroit = new AdroitMiddleware('action', [$actionResolver], [$responderResolver]);

// create a request containing an action identifier inside the routing result attribute
$request = ServerRequestFactory::fromGlobals()->withAttribute('action', 'helloAction');

// and run adroit
$response = $adroit($request, new Response());
$emitter = new SapiEmitter();
$emitter->emit($response);

如你所见,你也可以使用简单的可调用项作为操作和响应者。

Adroit本身不依赖于具体的PSR-7实现,这意味着你应该能够在不遇到问题的前提下在你的设置中使用它。只是为了单元测试,Adroit依赖于zendframework/zend-diactoros作为PSR-7实现。

中间件钩子

Adroit提供了几个钩子,以保持与标准中间件管道的灵活性,同时实现ADR范式。

您可以使用以下钩子来操纵ADR本身所需中间件执行过程中的事物。

// Gets piped in front of the ActionResolverMiddleware
$adroit->beforeResolveAction($yourMiddleware);

// Gets piped in front of the ActionExecutorMiddleware
$adroit->beforeExecuteAction($yourMiddleware);

// Gets piped in front of the ResponderResolverMiddleware
$adroit->beforeResolveResponder($yourMiddleware);

// Gets piped in front of the ResponderExecutorMiddleware
$adroit->beforeExecuteResponder($yourMiddleware);

这些钩子提供了很大的灵活性,但灵活性越大,责任也越大;请注意,钩子命名为"before",因此要实现中间件。

function (ServerRequestInterface $request, ResponseInterface $response, callable $next = null) {

    // Your awesome code

    if ($next)
        $response = $next($request, $response);
    }

    return $response;
}

当然,您可以以不同的方式实现它,但这不会触及钩子名称中的"before"。请注意这一点!

路由

为了避免外部依赖,我们从Adroit中移除了路由,因为可以使用任何您喜欢的路由机制来实现这一点。您只需确保将操作标识符设置为所选请求属性,并告诉ActionMiddleware在哪里查找它。

许可证

Adroit在Apache 2.0许可证下发布。