lenderspender/laravel-state-transition-workflow

状态转换工作流程

4.1.0 2024-04-09 12:12 UTC

This package is auto-updated.

Last update: 2024-09-09 13:04:03 UTC


README

此包为您的 Laravel 模型添加状态转换工作流程。允许您指定转换以及如何处理这些转换。

为了展示如何使用此包,让我们描绘以下场景。

一个事务可以有三个状态 CREATEDFAILEDSUCCESS。在状态间转换时,您可能希望对这种转换进行操作,例如发送成功邮件。您可能只想允许从 SUCCESSFAILED 的转换,而不是相反。

事务模型看起来像

use LenderSpender\StateTransitionWorkflow\HasStateTransitions;

/**
 * @property \App\Enums\TransactionState $state
 */
class Transaction extends Model
{
    use HasStateTransitions;

    protected function registerStateTransitions(): void
    {
        $this->addState('status')
            ->allowTransition(TransactionState::CREATED(), TransactionState::SUCCESS(), TransactionSuccessfullWorkflow::class)
            ->allowTransition(TransactionState::CREATED(), TransactionState::FAILED());
    }
}

这是 TransactionState 枚举的样子

use LenderSpender\LaravelEnums\Enum;
use LenderSpender\StateTransitionWorkflow\TransitionState;

/**
 * @method static self CREATED()
 * @method static self SUCCESS()
 * @method static self FAILED()
 */
class FooStates extends Enum implements TransitionState
{
    private const CREATED = 'created';
    private const SUCCESS = 'success';
    private const FAILED = 'failed';
}

这是 TransactionSuccessfullWorkflow 的样子

use Illuminate\Database\Eloquent\Model;
use LenderSpender\StateTransitionWorkflow\Transition;
use LenderSpender\StateTransitionWorkflow\Workflow;

class TransactionSuccessfullWorkflow extends Workflow
{
    public function __construct(FakeMailer $mailer)
    {
        $this->mailer = $mailer;
    }

    /**
     * @param \App\Models\Transaction $model
     */
    public function execute(Model $transaction, Transition $transition): void
    {
         $this->mailer->mail($transaction->email, 'Payment was sucessfull');
    }
}

这是您如何使用它的方法

$transaction = Transaction::find(1337);
$transaction->transitionStateTo(FooStates::SUCCESS());

$transaction->state == FooStates::SUCCESS; // true

安装

您可以通过 composer 安装此包

composer require lenderspender/laravel-state-transition-workflow

使用方法

该包提供了一个 HasStateTransitions 特性,您可以在任何希望支持状态的模型中使用它。

状态管理

注册状态字段

要为 $status 属性设置状态,您应该在模型中添加 HasStateTransitions 特性并实现 registerStateTransitions 方法。

use Illuminate\Database\Eloquent\Model;
use LenderSpender\StateTransitionWorkflow\HasStateTransitions;

/**
 * @property \App\Enums\TransactionState $state
 */
class Transaction extends Model
{
    use HasStateTransitions;

    protected function registerStateTransitions(): void
    {
        $this->addState('status');
    }
}

添加允许的转换

转换用于将模型的状态字段从一个转换到另一个。您需要指定哪些转换是允许的,以及转换时应启动哪个工作流程。默认情况下,所有转换均不允许。要允许转换,您应该在添加的状态上调用 allowTransition

State::FROM()State::TO() 的单个转换

class Transaction extends Model
{
    use HasStateTransitions;

    protected function registerStateTransitions(): void
    {
        $this->addState('status')
            ->allowTransitions(State::FROM(), State::TO());
    }
}

允许从 State::CREATED() 转换到 State::FAILED()State::SUCCESS()

use Illuminate\Database\Eloquent\Model;
use LenderSpender\StateTransitionWorkflow\HasStateTransitions;

class Transaction extends Model
{
    use HasStateTransitions;

    protected function registerStateTransitions(): void
    {
        $this->addState('status')
            ->allowTransitions(State::CREATED(), [State::FAILED(), State::SUCCESS());
    }
}        

允许从 State::CREATED()State::UPDATED() 转换到 State::FAILED()State::SUCCESS()

use LenderSpender\StateTransitionWorkflow\HasStateTransitions;

class Transaction extends Model
{
    use HasStateTransitions;

    protected function registerStateTransitions(): void
    {
        $this->addState('status')
            ->allowTransitions([State::CREATED(), State::UPDATED()], [State::FAILED(), State::SUCCESS()]);
    }
}

使用转换

您可以通过在模型上调用 transitionStateTo 方法来使用转换。

$transaction->transitionStateTo(State::SUCCESS());

默认情况下,该方法使用第一个注册的状态。当您添加了多个状态字段时,您应该指定要使用哪个字段。

$transaction->transitionStateTo(State::SUCCESS(), 'status');

当状态转换不被允许时,将抛出 LenderSpender\StateTransitionWorkflow\Exceptions\TransitionNotAllowedException 异常。

列出允许的状态转换

要了解可以执行哪些允许的状态转换,您可以在模型上调用 getAvailableStateTransitions

$transaction->getAvailableStateTransitions();

默认情况下,该方法使用第一个注册的状态。当您添加了多个状态字段时,您应该指定要使用哪个字段。

$transaction->getAvailableStateTransitions('status');

状态工作流程

当将模型从一种状态转换到另一种状态时,您有时希望对这种转换进行操作。或者甚至阻止转换发生。这就是状态工作流程的用武之地。

创建工作流程

自动在执行工作流程后处理转换

use Illuminate\Database\Eloquent\Model;
use LenderSpender\StateTransitionWorkflow\Transition;
use LenderSpender\StateTransitionWorkflow\Workflow;

class PaidWorkflow extends Workflow
{
    /**
     * @param \App\Model\Transaction $model
     */
    public function execute(Model $transaction, Transition $transition): void
    {
         dump('This is executed before the transition');
    }
}

在工作流程中处理转换

use Illuminate\Database\Eloquent\Model;
use LenderSpender\StateTransitionWorkflow\Transition;
use LenderSpender\StateTransitionWorkflow\Workflow;

class PaidWorkflow extends Workflow
{
    /**
     * @param \App\Model\Transaction $model
     */
    public function execute(Model $transaction, Transition $transition): void
    {
         dump('This is executed before the transition');
         $transition->execute();
         dump('This is executed after the transition');
    }
}

排队转换

当您想在转换前后执行一些繁重的操作时,您可以通过在工作流程上实现 ShouldQueue 接口来排队转换。

use Illuminate\Contracts\Queue\ShouldQueue;
use LenderSpender\StateTransitionWorkflow\Workflow;

class PaidWorkflow extends Workflow implements ShouldQueue
{
}

阻止转换

您可以通过覆盖工作流程中的 isAllowed 方法并返回 false 来阻止转换。

use LenderSpender\StateTransitionWorkflow\Workflow;

class PaidWorkflow extends Workflow
{
    public function isAllowed(Transition $transition): bool
    {
        return false;
    }
}

将工作流程注册到状态转换

class Transaction extends Model
{
    use HasStateTransitions;

    protected function registerStateTransitions(): void
    {
        $this->addState('status')
            ->allowTransitions(State::CREATED(), State::SUCCESS(), PaidWorkflow::class);
    }
}