bakame/spec

PHP 中的规范

维护者

详细信息

github.com/bakame-php/spec

源代码

资助包维护!
nyamsprod

2.0.0 2022-05-16 07:21 UTC

This package is auto-updated.

Last update: 2024-08-23 10:28:15 UTC


README

此包为 PHP 提供了对规范模式的支持。它通过卸载所有繁琐的工作来帮助利用复杂的规范。实现规范模式变得简单,同时将所有逻辑连接留给了包。

虽然与框架无关,但您可以将此包轻松集成到任何 PHP 框架中。

Software License Build Latest Version Total Downloads Sponsor development of this project

系统需求

您需要

  • PHP >= 8.0 但建议使用 PHP 的最新稳定版本

安装

使用 composer

composer require bakame/spec

或下载库并

  • 使用任何其他 PSR-4 兼容的自动加载器。
  • 使用如下所示的包自动加载脚本
require 'path/to/spec/repo/autoload.php';

use Bakame\Specification\Chain;

$spec = Chain::one(new Rule1())
    ->and(new Rule2(), new Rule3())
    ->orNot(new Rule4());

$spec->isSatisfiedBy($subject);

这是什么?

"规范模式是一种特定的软件设计模式,通过使用布尔逻辑将业务规则链接在一起,可以重新组合业务规则。该模式通常用于领域驱动设计的上下文中。" -- 维基百科

用法

需要满足的每个规则都必须实现 Bakame\Specification\Specification 接口。

此接口仅包含一个方法 isSatisfiedBy(mixed $subject): bool。该方法不应 抛出 异常,但如果它确实抛出异常,则没有机制 MUST 停止异常在方法外部传播。

以下是一个快速示例,说明如何使用此包。

首先,我们创建一个实现规范类。

<?php

use Bakame\Specification\Specification;

final class OverDueSpecification implements Specification
{
    public function __construct(
        private DateTimeImmutable $date = new DateTimeImmutable('NOW', new DateTimeZone('UTC'))
    ) {
    }

    public function isSatisfiedBy(mixed $subject) : bool
    {
        return $subject instanceof Invoice
            && $subject->getDueDate() < $this->date;
    }
}

然后使用 Bakame\Specification\Chain 类和创建的所有规范,我们根据业务规则应用所有规范。

以下是如何使用库对维基百科示例进行适配。

<?php

use Bakame\Specification\Chain;

$overDue = new OverDueSpecification();
$noticeSent = new NoticeSentSpecification();
$inCollection = new InCollectionSpecification();

$sendToCollection = Chain::one($overDue)
    ->and($noticeSent)
    ->andNot($inCollection);

foreach ($service->getInvoices() as $invoice) {
    if ($sendToCollection->isSatisfiedBy($invoice)) {
        $invoice->sendToCollection();
    }
}

Bakame\Specification\Chain 类公开以下逻辑链接方法

为了启动一个新的规范逻辑链,类公开了 4 个命名构造函数

Bakame\Specification\Chain 的所有方法都接受可变数量的 Bakame\Specification\Specification 实现类,除了 Chain::not 方法,它不接受任何参数。

创建更复杂的规则变得非常简单,同样它们的维护也是如此。

有关如何验证主题列表的技巧。

数组

要过滤主题数组,可以使用 array_filter 函数

<?php
$invoiceCollection = array_filter(
    fn (Invoice $invoice): bool => $sendToCollection->isSatisfiedBy($invoice),
    $respository->getInvoices()
);

foreach ($invoiceCollection as $invoice) {
    $invoice->sendToCollection();
}

可遍历

要过滤可遍历结构或通用迭代器,可以使用 CallbackFilterIterator 类。

<?php
$invoiceCollection = new CallbackFilterIterator(
    $respository->getInvoices(),
    fn (Invoice $invoice): bool => $sendToCollection->isSatisfiedBy($invoice),
);

foreach ($invoiceCollection as $invoice) {
    $invoice->sendToCollection();
}

集合

该包可以直接用于支持 filter 方法的集合,如 Doctrine 集合类。

<?php
$invoiceCollection = $respository->getInvoices()->filter(
    fn (Invoice $invoice): bool => $sendToCollection->isSatisfiedBy($invoice)
);

foreach ($invoiceCollection as $invoice) {
    $invoice->sendToCollection();
}

集合宏

对于 Laravel 集合的替代方法是注册一个宏

<?php

declare(strict_types=1);

use Bakame\Specification\Specification;
use Illuminate\Support\Collection;

Collection::macro('satisfies', fn (Specification $specification): Collection =>
    $this->filter(
        fn ($item): bool => $specification->isSatisfiedBy($item);
    )
);

然后按以下方式使用

$invoiceCollection = $invoices->all()->satifies($sendToCollection);
foreach ($invoiceCollection as $invoice) {
    $invoice->sendToCollection();
}

贡献

欢迎贡献,并将得到充分认可。请参阅 CONTRIBUTINGCODE OF CONDUCT 了解详情。

测试

  • 具有 PHPSpec 测试套件
  • 具有使用 PHP CS Fixer 的编码风格合规性测试套件。
  • 该文档使用了PHPStanPsalm进行代码分析合规性测试套件。

要运行测试,请在项目文件夹中运行以下命令。

$ composer test

安全

如果您发现任何与安全相关的问题,请发送电子邮件至nyamsprod@gmail.com,而不是使用问题跟踪器。

致谢

署名

该包是greydnlsgreydnls/spec上工作的分支。

许可证

MIT许可证(MIT)。有关更多信息,请参阅许可证文件