ammit-php/ammit

[DDD] 稳定的框架无关命令解析器

安装: 14

依赖者: 0

建议者: 0

安全性: 0

星标: 3

关注者: 7

分支: 2

开放问题: 7

类型:项目

v1.0.0-beta5 2017-05-04 06:56 UTC

README

# Ammit

PHP7 DDD v1.0.0 beta v2.0.0 never SemVer Build Status Code Quality Code Coverage Dependency Status

一个轻量级、稳定且框架无关的命令解析器库

目前正在接受实战测试(尚未标记为1.0.0)

  1. 库的功能
  2. 如何使用它?
  3. 库不做什么?
  4. 为什么?
  5. 它是如何工作的?
  6. 实用主义?
  7. 想要贡献?
  8. Ammit?

一个命令是一个简单的、有良好命名的DTO,反映了用户的意图

因此它应该是不可变的

  • RegisterUserCommand
  • DisableUserCommand
  • BookCargoCommand

库的功能?

  • 它提供了一个辅助工具,可以轻松地从PSR-7 HTTP请求(或CLI输入)中提取标量数据,以实例化一个不可变的命令。
  • 它允许实现干净的命令(没有公共字段)。
  • 它设计为简单的UI验证框架,无需依赖。
  • 它设计用来简化UI验证与领域验证的关注点分离

Simple Spec

如何使用它?

composer require ammit-php/ammit

示例

实现一个RegisterUserCommandResolver,它将PSR-7 ServerRequestInterface映射到RegisterUserCommand。在创建RegisterUserCommand之前,它将执行UI验证。

RegisterUserController.php

$registerUserCommandResolver = new RegisterUserCommandResolver();
try {
    $command = $registerUserCommandResolver->resolve($request);
} catch (AbstractNormalizableCommandResolverException $e) {
    // Return a JSON error following jsonapi.org's format
    // @see https://jsonapi.fullstack.org.cn/examples/#error-objects-basics
    return JsonResponse::fromJsonString(
        json_encode(
            $e->normalize()
        ), 
        406
    );
}

try {
    $this->userService->registerUser($command);
} catch(DomainException $e) {
   // ...
}
// ...

RegisterUserCommandResolver.php

/**
 * Resolve a PSR-7 Request into a RegisterUserCommand (Data Transfer Object)
 */
class RegisterUserCommandResolver extends AbstractPureCommandResolver
{
    /**
     * @inheritdoc
     */
    public function resolve(ServerRequestInterface $request): RegisterUserCommand
    {
        $commandConstructorValues = $this->resolveRequestAsArray($request);

        // We are using variadic function here (https://wiki.php.net/rfc/variadics)
        return new RegisterUserCommand(...$commandConstructorValues);
    }

    /**
     * @inheritDoc
     */
    protected function validateThenMapAttributes(ServerRequestInterface $request): array
    {
        // $id = $_GET['id']
        $id = $this->queryStringValueValidator->mustBeString(
            $request,
            'id'
        );

        // $firstName = $_POST['firstName']
        $firstName = $this->attributeValueValidator->mustBeString(
            $request,
            'firstName'
        );

        // $lastName = $_POST['lastName']
        $lastName = $this->attributeValueValidator->mustBeString(
            $request,
            'lastName'
        );

        // $email = $_POST['email']
        $email = $this->attributeValueValidator->mustBeString(
            $request,
            'email'
        );

        // Will be injected directly in RegisterUserCommand::__construct(...$args)
        // as variadic function
        $commandConstructorValues = [
            $id,
            $firstName,
            $lastName,
            $email
        ];

        return $commandConstructorValues;
    }
}

在Symfony中使用它:https://symfony.ac.cn/doc/current/request/psr7.html

在Laravel中使用它:待定

公共API

纯扩展AbstractPureCommandResolver
实用扩展AbstractPragmaticCommandResolver

库不做什么?

  • 它不是设计来替代Symfony Form Component的。
  • 它不是设计来创建复杂验证的。它的目标是验证简单的标量。然而,它仍然允许"实用"的复杂UI验证,用于原型设计/快速应用程序开发。
  • 它不是设计来使用PHP反射的。它只意味着使用命令构造函数。

为什么?

我们曾经使用Symfony Form Component将HTTP请求映射并验证到我们的命令。

但这太复杂了,并且hacky。并且太容易将我们的领域验证放入FormType。然后“忘记”将其放回我们的领域。

此外,我们希望预见不可变类

它是如何工作的?

Complete Spec

它内部使用\Closure,以便能够捕获所有\Exception。否则,它只会显示一个验证问题。而我们希望像表单一样一次性看到所有验证问题。

实用主义?

您可能需要在UI中放置一些领域验证。有时我们在原型设计时需要进行一些快速应用程序开发。并且知道我们将在不久的将来偿还我们的技术债务。

使用Ammit,您将使用我们的AbstractPragmaticCommandhenResolver实用)而不是我们的AbstractPureCommandResolver)辅助工具。它将允许您使用更复杂的验证,例如示例中的uuid验证。

$email = $attributeValueValidator->mustBeUuid(
    $request,
    'id'
);

缺少验证。您仍然可以注入自己的。

想要贡献?

阅读UBIQUITOUS_LANGUAGE_DICTIONARY.md

初始化 Docker 容器:docker-compose up -d

Composer 安装:docker-compose run --rm composer install

使用容器:docker/bin/php -v (首先执行 chmod +x docker/bin/php

添加单元测试后:docker/bin/php bin/atoum

Ammit?

Ammit 是一位古代埃及女神,与心脏称重有关。她吞噬那些被认为不够纯洁,无法继续前往奥西里斯和永生之旅的人类灵魂。