Laravel工作流用状态模式吗

wen PHP项目 2

本文目录导读:

Laravel工作流用状态模式吗

  1. 核心逻辑:状态模式的定义
  2. Laravel 中的实现方案
  3. 实际项目中的最佳实践
  4. 代码示例(基于 spatie 包)

在 Laravel 工作流开发中,状态模式确实是核心的底层设计思想,但实际应用中很少直接套用“标准状态模式”的类结构,而是借助 Laravel 特有的工具(如状态机包、Eloquent 事件、管道)来实现更灵活的实现。

核心逻辑:状态模式的定义

标准状态模式允许对象在内部状态改变时改变其行为,这完全符合工作流(Workflow)的需求:

  • 每个状态定义允许的转换
  • 状态转换时触发业务逻辑
  • 对象的行为随当前状态而变化

Laravel 中的实现方案

主流方案:状态机包(如 spatie/laravel-model-states

这是最接近状态模式的实现:

// 定义状态
class PendingState extends State
{
    public function approve(): State
    {
        $this->performEvent('approve');
        return new ApprovedState($this->model);
    }
    public function reject(): State
    {
        $this->performEvent('reject');
        return new RejectedState($this->model);
    }
}
class ApprovedState extends State
{
    public function reprocess(): State
    {
        return new PendingState($this->model);
    }
}
// 使用
$order = Order::find(1);
$order->state->transition(new ApprovedState($order));

经典实现:cerbero90/laravel-workflow 或自定义

直接复现 GoF 状态模式的类结构:

// 上下文
class OrderContext
{
    private OrderState $state;
    public function __construct(Order $order)
    {
        $this->state = match($order->status) {
            'pending' => new PendingState(),
            'paid' => new PaidState(),
            default => throw new \Exception()
        };
    }
    public function proceed(OrderAction $action): void
    {
         // 委托给当前状态处理
        $this->state->handle($this, $action);
    }
    public function setState(OrderState $state): void
    {
        $this->state = $state;
    }
}
// 状态接口
interface OrderState
{
    public function handle(OrderContext $context, OrderAction $action): void;
}
class PendingState implements OrderState 
{
    public function handle(OrderContext $context, OrderAction $action): void
    {
        if ($action->isPay()) {
            // 执行业务逻辑
            $context->setState(new PaidState());
        }
    }
}

轻型方案:Eloquent + 策略模式(简易替代)

不严格遵循状态模式,但能实现类似效果:

// Eloquent Model
class Order extends Model
{
    protected $states = [
        'pending' => PendingHandler::class,
        'paid' => PaidHandler::class,
    ];
    // 状态变更验证
    protected $validTransitions = [
        'pending' => ['paid', 'cancelled'],
        'paid' => ['shipped'],
        'shipped' => ['delivered'],
    ];
    public function transitionTo(string $newState): void
    {
        // 检查转换合法性
        if (!in_array($newState, $this->validTransitions[$this->status] ?? [])) {
            throw new InvalidTransitionException();
        }
        $this->status = $newState;
        $this->save();
        // 触发业务逻辑
        (new $this->states[$newState]($this))->handle();
    }
}

实际项目中的最佳实践

个人推荐的工具栈

  1. 简单工作流:Eloquent status 字段 + transition()方法
  2. 复杂工作流spatie/laravel-model-states
  3. 业务流程引擎symfony/workflow (Laravel 可集成)

关键决策点

维度 标准状态模式 Laravel 实用方案
状态数量 ✅ 2-10 个 ✅ 任何数量
转换逻辑复杂性 状态越多,类越多 配置驱动,易于扩展
数据持久化 需要额外实现 天然支持 Eloquent
事件监听 需手动实现 原生支持 Laravel Events
团队可维护性 可能过度工程 更适合 Laravel 开发者

代码示例(基于 spatie 包)

// app/Models/States/TicketState.php
abstract class TicketState extends State
{
    abstract public function statusLabel(): string;
    public function assignTo(User $user): void
    {
        $this->model->assigned_to = $user->id;
        $this->model->save();
    }
}
// app/Models/States/Pending.php
class Pending extends TicketState
{
    public function statusLabel(): string
    {
        return '待处理';
    }
    public function startWork(): State
    {
        // 验证权限
        // 记录日志
        event(new TicketStarted($this->model));
        return new InProgress($this->model);
    }
}
// Model
class Ticket extends Model
{
    use HasStates;
    protected $casts = [
        'state' => TicketState::class,
    ];
    public function startWork(): void
    {
         // 转换状态,自动验证合法性
        $this->state->transitionTo(InProgress::class);
    }
}

Laravel 工作流在概念上完全使用状态模式,但在实现上:

推荐使用

  • spatie/laravel-model-states(接近标准状态模式)
  • Eloquent + 自定义状态验证(简易场景)

不推荐

  • 手动实现完整的 GoF 状态模式代码结构(复杂且不必要)
  • 在单个控制器/Service 中写 if/else 处理所有状态转换

核心原则:利用 Laravel 生态提供的工具(状态机包、Eloquent、事件),而不是重新发明轮子,这能让你获得状态模式的所有优点(可扩展、行为封装、状态转换可控),同时保持 Laravel 代码的简洁和可维护性。

抱歉,评论功能暂时关闭!