ringierimu/state-workflow

Laravel 的状态管理流程

2.3.0 2023-05-31 11:12 UTC

README

在 Laravel 中实现 Symfony Workflow 组件

工作流程由状态和动作组成,用于从一个地方移动到另一个地方。动作被称为转换,它描述了如何从一个状态转换到另一个状态。

安装

$ composer require ringierimu/state-workflow 

对于低于 5.5 版本的 Laravel,运行上述脚本后此步骤很重要。

  • 打开您的 config/app.php 文件并添加自定义服务提供者
Ringierimu\StateWorkflow\StateWorkflowServiceProvider::class

发布 config/workflow.php 文件

$ php artisan vendor:publish --provider="Ringierimu\StateWorkflow\StateWorkflowServiceProvider"

运行迁移

$ php artisan migrate

配置

  1. 打开 config/workflow.php 并进行配置
// this should be your model name in camelcase. eg. PropertyListing::Class => propertyListing
'post' => [
        // class of your domain object
        'class' => \App\Post::class,

        // Register subscriber for this workflow which contains business rules. Uncomment line below to register subscriber
        //'subscriber' => \App\Listeners\UserEventSubscriber::class,
        
        // property of your object holding the actual state (default is "current_state")
        //'property_path' => 'current_state', //uncomment this line to override default value

        // list of all possible states
        'states' => [
            'new',
            'pending_activation',
            'activated',
            'deleted',
            'blocked'
        ],

        // list of all possible transitions
        'transitions' => [
            'create' => [
                'from' => ['new'],
                'to' => 'pending_activation',
            ],
            'activate' => [
                'from' => ['pending_activation'],
                'to' =>  'activated',
            ],
            'block' => [
                'from' => ['pending_activation', 'activated'],
                'to' => 'blocked'
            ],
            'delete' => [
                'from' => ['pending_activation', 'activated', 'blocked'],
                'to' =>  'deleted',
            ],
        ],
    ],
  1. HasWorkflowTrait 添加到您的模型类中以支持工作流程
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use Ringierimu\StateWorkflow\Traits\HasWorkflowTrait;

/**
 * Class Post
 * @package App
 */
class Post extends Model
{
    use HasWorkflowTrait;
}

用法

管理状态/工作流程

<?php
use App\Post;

$post = new Post();

//Apply transition
$post->applyTransition("create");
$post = $post->refresh();

//Return current_state value
$post->state(); //pending_activation

//Check if this transition is allowed
$post->canTransition("activate"); // True

//Return Model state history
$post->stateHistory();

触发事件

每个步骤都会依次触发三个事件

  • 针对每个工作流程的事件
  • 针对相关工作流程的事件
  • 针对具有特定转换或状态名称的相关工作流程的事件

在状态/工作流程转换期间,以下事件按以下顺序触发

  1. 验证转换是否始终允许。它们的事件监听器在每次调用 workflow()->can()workflow()->apply()workflow()->getEnabledTransitions() 时被调用。守卫事件
workflow.guard
workflow.[workflow name].guard
workflow.[workflow name].guard.[transition name]
  1. 主题即将离开一个状态。离开事件
workflow.leave
workflow.[workflow name].leave
workflow.[workflow name].leave.[state name]
  1. 主题正在经历这个转换。转换事件
workflow.transition
workflow.[workflow name].transition
workflow.[workflow name].transition.[transition name]
  1. 主题即将进入一个新的状态。此事件在主题状态更新之前触发。进入事件
workflow.enter
workflow.[workflow name].enter
workflow.[workflow name].enter.[state name]
  1. 主题已进入状态并更新。进入事件
workflow.entered
workflow.[workflow name].entered
workflow.[workflow name].entered.[state name]
  1. 主题已完成此转换。完成事件
workflow.completed
workflow.[workflow name].completed
workflow.[workflow name].completed.[transition name]

订阅者

创建订阅类以侦听这些事件,并且该类应该 extends WorkflowSubscriberHandler

要在订阅者中注册用于侦听特定事件的方法,请使用以下格式的方法名

  • on[Event] - onGuard()
  • on[Event][Transition/State name] - onGuardActivate()

注意

  • 方法名必须以 on 关键字开头,否则将被忽略。
  • Subscriber 类必须注册在 workflow.php 配置文件中,并具有适当的流程配置。
  • Subscriber 类必须扩展 WorkflowSubscriberHandler
  • GuardTransitionCompleted 事件使用转换名称。
  • LeaveEnterEntered 事件使用状态名称。
<?php namespace App\Listeners;

use Ringierimu\StateWorkflow\Events\EnteredEvent;
use Ringierimu\StateWorkflow\Events\EnterEvent;
use Ringierimu\StateWorkflow\Events\GuardEvent;
use Ringierimu\StateWorkflow\Events\LeaveEvent;
use Ringierimu\StateWorkflow\Events\TransitionEvent;
use Ringierimu\StateWorkflow\Subscribers\WorkflowSubscriberHandler;

/**
 * Class PostEventSubscriber
 * @package App\Listeners
 */
class UserEventSubscriber extends WorkflowSubscriberHandler
{
    /**
     * Handle workflow guard events.
     * 
     * @param GuardEvent $event
     */
    public function onGuardActivate($event)
    {
        $user = $event->getOriginalEvent()->getSubject();

        if (empty($user->dob)) {
            // Users with no dob should not be allowed
            $event->getOriginalEvent()->setBlocked(true);
        }
    }
    
    /**
     * Handle workflow leave event.
     * 
     * @param LeaveEvent $event
     */
    public function onLeavePendingActivation($event)
    {
    }
    
    /**
     * Handle workflow transition event.
     * 
     * @param TransitionEvent $event
     */
    public function onTransitionActivate($event)
    {
    }
    
    /**
     * Handle workflow enter event.
     * 
     * @param EnterEvent $event
     */
    public function onEnterActivated($event)
    {
    }

    /**
     * Handle workflow entered event.
     * 
     * @param EnteredEvent $event
     */
    public function onEnteredActivated($event)
    {
    }
}

事件方法

每个工作流程事件都有一个 Event 实例。这意味着每个事件都可以访问以下信息

  • getOriginalEvent():返回触发事件的父事件,该事件具有以下子方法
    • getSubject():返回触发事件的对象。
    • getTransition():返回触发事件的转换。
    • getWorkflowName():返回触发事件的流程名称的字符串。
    • isBlocked():如果转换被阻止则返回 true/false。
    • setBlocked():设置阻止值。

Artisan 命令

Symfony 工作流使用 GraphvizDumper 通过 dot 命令创建工作流程图像。该 dot 命令是 Graphviz 的一部分。

您需要下载 dot 命令才能使用此命令。https://graphviz.gitlab.io/download/

用法

php artisan workflow:dump workflow_name