lenderspender / laravel-state-transition-workflow
状态转换工作流程
Requires
- php: ^8.2
- laravel/framework: ^11.0 | ^10.0
- spatie/laravel-queueable-action: ^2.14
Requires (Dev)
- lenderspender/php-cs-fixer-rules: dev-master
- orchestra/testbench: ^9.0
- phpstan/phpstan: ^1.3.1
- phpunit/phpunit: ^10.0
README
此包为您的 Laravel 模型添加状态转换工作流程。允许您指定转换以及如何处理这些转换。
为了展示如何使用此包,让我们描绘以下场景。
一个事务可以有三个状态 CREATED
、FAILED
和 SUCCESS
。在状态间转换时,您可能希望对这种转换进行操作,例如发送成功邮件。您可能只想允许从 SUCCESS
到 FAILED
的转换,而不是相反。
事务模型看起来像
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); } }