PHP code example of wiseadmin / wise-workflow
1. Go to this page and download the library: Download wiseadmin/wise-workflow library . Choose the download type require .
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
wiseadmin / wise-workflow example snippets
use wise\workflow\WorkflowEngine;
use wise\workflow\DatabaseMarkingStore;
$engine = new WorkflowEngine(new DatabaseMarkingStore());
use wise\workflow\Workflow;
use wise\workflow\Place;
use wise\workflow\Transition;
// 创建一个订单审批工作流
$workflow = new Workflow('order_approval');
// 添加状态节点(Place)
$workflow->addPlace(new Place('draft')); // 草稿
$workflow->addPlace(new Place('submitted')); // 已提交
$workflow->addPlace(new Place('reviewing')); // 审核中
$workflow->addPlace(new Place('approved')); // 已通过
$workflow->addPlace(new Place('rejected')); // 已拒绝
// 设置初始状态
$workflow->setMetadata(['initial_place' => 'draft']);
// 添加转换规则(Transition)
// 格式:new Transition(name, from, to)
$workflow->addTransition(new Transition('submit', 'draft', 'submitted'));
$workflow->addTransition(new Transition('assign', 'submitted', 'reviewing'));
$workflow->addTransition(new Transition('approve', 'reviewing', 'approved'));
$workflow->addTransition(new Transition('reject', 'reviewing', 'rejected'));
$workflow->addTransition(new Transition('resubmit', 'rejected', 'draft'));
use wise\workflow\WorkflowRegistry;
WorkflowRegistry::add($workflow);
use wise\workflow\WorkflowEngine;
use wise\workflow\WorkflowRegistry;
use wise\workflow\DatabaseMarkingStore;
// 创建引擎实例
$store = new DatabaseMarkingStore();
$engine = new WorkflowEngine($store);
// 获取工作流
$workflow = WorkflowRegistry::get('order_approval');
// 1. 初始化工作流状态(将订单设为初始状态)
$engine->init($workflow, 'order:1001');
// 2. 检查是否可以提交
if ($engine->can($workflow, 'order:1001', 'submit')) {
// 3. 执行提交转换
$engine->apply($workflow, 'order:1001', 'submit', [
'operator' => 'admin',
'remark' => '提交审批',
]);
echo "提交成功!\n";
}
// 4. 获取当前状态
$marking = $engine->getMarking('order:1001');
print_r($marking); // 输出:['submitted' => 1]
// 5. 获取可用的转换
$enabled = $engine->getEnabledTransitions($workflow, 'order:1001');
foreach ($enabled as $transition) {
echo $transition->getName() . "\n"; // 输出:assign
}
namespace wise\workflow;
class Place
{
/**
* @param string $name 状态名称(唯一标识)
*/
public function __construct(string $name);
public function getName(): string;
}
// 基本用法
$place = new Place('draft');
// 批量添加状态
$workflow->addPlace(new Place('draft'));
$workflow->addPlace(new Place('submitted'));
$workflow->addPlace(new Place('approved'));
namespace wise\workflow;
class Transition
{
/**
* @param string $name 转换名称(唯一标识)
* @param string|array $from 源状态(单个或多个)
* @param string|array $to 目标状态(单个或多个)
* @param callable|null $guard 守卫条件回调(可选)
*/
public function __construct(string $name, $from, $to, ?callable $guard = null);
public function getName(): string;
public function getFrom(): array;
public function getTo(): array;
public function getGuard(): ?callable;
}
// 基本转换:从 draft 到 submitted
$transition = new Transition('submit', 'draft', 'submitted');
// 多源状态:draft 或 rejected 都可以提交
$transition = new Transition('submit', ['draft', 'rejected'], 'submitted');
// 带守卫条件:只有金额小于 1000 的订单才能自动通过
$transition = new Transition('auto_approve', 'reviewing', 'approved', function ($marking, $context) {
return $context['amount'] < 1000;
});
namespace wise\workflow;
class Workflow
{
/**
* @param string $name 工作流名称(全局唯一)
* @param array $places Place 对象数组
* @param array $transitions Transition 对象数组
* @param string|null $initialPlace 初始状态
*/
public function __construct(string $name, array $places = [], array $transitions = [], $initialPlace = null);
public function addPlace(Place $place): void;
public function addTransition(Transition $transition): void;
public function setMetadata(array $metadata): void;
public function getName(): string;
public function getPlaces(): array;
public function getTransitions(): array;
public function getInitialPlace(): ?string;
public function getMetadata(): array;
}
namespace wise\workflow;
class WorkflowRegistry
{
/** 注册一个工作流 */
public static function add(Workflow $workflow): void;
/** 获取指定名称的工作流 */
public static function get(string $name): Workflow;
/** 获取所有已注册的工作流 */
public static function all(): array;
/** 判断工作流是否存在 */
public static function has(string $name): bool;
/** 清除所有已注册的工作流 */
public static function clear(): void;
/** 从数据库加载所有启用的工作流 */
public static function loadFromDatabase(): void;
}
// 方式一:代码静态注册
$workflow = new Workflow('order_approval');
// ... 添加 places 和 transitions
WorkflowRegistry::add($workflow);
// 方式二:数据库动态注册
// 先在 workflow_definition 表中插入配置,然后:
WorkflowRegistry::loadFromDatabase();
namespace wise\workflow;
class WorkflowEngine
{
/**
* @param MarkingStoreInterface $markingStore 状态存储(必须)
* @param mixed $eventService 事件服务(可选)
* @param mixed $permissionService 权限服务(可选)
* @param mixed $historyModel 历史记录模型(可选)
*/
public function __construct(
MarkingStoreInterface $markingStore,
$eventService = null,
$permissionService = null,
$historyModel = null
);
}
// 订单
$subject = 'order:1001';
// 工单
$subject = 'ticket:W-2024-001';
// 也可以自定义格式
$subject = 'document_approval_42';
use app\common\facade\Workflow;
use app\common\facade\Workflow;
// 创建订单后初始化工作流
$order = Order::create([...]);
Workflow::init('order_approval', $order);
// 在控制器中处理审核
public function approve($orderId)
{
$order = Order::find($orderId);
// 检查权限(自动通过 GuardListener 处理)
if (!Workflow::can('order_approval', $order, 'approve')) {
return $this->error('无权执行此操作或当前状态不允许');
}
// 执行转换
Workflow::apply('order_approval', $order, 'approve', [
'operator' => session('admin_id'),
'remark' => '审核通过',
]);
// 获取当前可执行操作
$transitions = Workflow::transitions('order_approval', $order);
// 判断状态
$isApproved = Workflow::is('order_approval', $order, 'approved');
return $this->success('审核完成', compact('transitions', 'isApproved'));
}
namespace wise\workflow;
class GuardListener
{
/**
* @param mixed $permissionService 权限服务(如 PermissionService)
* @param bool $enabled 是否启用权限检查
*/
public function __construct($permissionService = null, bool $enabled = true);
}
// 定义转换时指定权限标识
$transition = new Transition(
'approve', // 转换名称
'reviewing', // 源状态
'approved', // 目标状态
function ($marking, $context) use ($permissionService) {
// 此处传入权限检查回调
return $permissionService->check('order.approve');
}
);
Workflow::apply('order_approval', $order, 'approve', [
'user_id' => session('admin_id'), // 操作人ID
'guard' => 'workflow.order.approve', // 需要检查的权限标识
'remark' => '审核通过',
]);
use think\facade\Event;
// 监听转换后事件 - 发送通知
Event::listen('workflow.after_transition', function ($params) {
$workflow = $params['workflow'];
$transition = $params['transition'];
$subject = $params['subject'];
$context = $params['context'];
// 只处理特定工作流
if ($workflow->getName() !== 'order_approval') {
return;
}
switch ($transition->getName()) {
case 'submit':
// 订单提交后通知审核员
Notifier::send('reviewer', "新订单 {$subject} 等待审核");
break;
case 'approve':
// 审核通过后更新订单状态
Order::where('order_no', $subject)
->update(['status' => 'approved', 'approved_at' => date('Y-m-d H:i:s')]);
break;
case 'reject':
// 审核拒绝后通知提交人
Notifier::send($context['submitter_id'], "订单 {$subject} 审核被拒绝");
break;
}
});
// 监听特定转换事件
Event::listen('workflow.order_approval.approve', function ($params) {
// 只针对 order_approval 工作流的 approve 转换
Log::record("订单 {$params['subject']} 已被审核通过", 'workflow');
});
// 在 before_transition 事件中进行业务校验
Event::listen('workflow.before_transition', function ($params) {
$subject = $params['subject'];
$context = $params['context'];
// 业务校验:审核通过前检查金额
if ($params['transition']->getName() === 'approve') {
$order = Order::find($subject);
if ($order->amount > 100000 && empty($context['manager_approved'])) {
throw new \Exception('大额订单需要经理审批');
}
}
});
// 通过引擎
$history = $engine->getHistory('order:1001', 20);
// 通过 Facade
$history = Workflow::history('order_approval', $order, 20);
// 通过模型直接查询
$history = \wise\workflow\model\WorkflowHistory::where('subject', 'order:1001')
->order('id', 'desc')
->select();
[
'id' => 42, // 记录ID
'subject' => 'order:1001', // 流程实例标识
'transition_name' => 'approve', // 转换名称
'from_place' => 'reviewing', // 源状态
'to_place' => 'approved', // 目标状态
'context' => '{"remark":"审核通过"}', // 上下文(JSON)
'user_id' => 1, // 操作用户ID
'ip' => '192.168.1.100', // 操作IP
'user_agent' => 'Mozilla/5.0...', // User-Agent
'create_time' => '2024-01-15 14:30:00', // 创建时间
]
namespace plugin\myplugin;
use wise\workflow\Workflow;
use wise\workflow\Place;
use wise\workflow\Transition;
class Plugin
{
/**
* 获取工作流定义
*
* @return Workflow[]
*/
public static function getWorkflowDefinitions(): array
{
$workflow = new Workflow('my_approval');
$workflow->addPlace(new Place('draft'));
$workflow->addPlace(new Place('submitted'));
$workflow->addPlace(new Place('approved'));
$workflow->addPlace(new Place('rejected'));
$workflow->addTransition(new Transition('submit', 'draft', 'submitted'));
$workflow->addTransition(new Transition('approve', 'submitted', 'approved'));
$workflow->addTransition(new Transition('reject', 'submitted', 'rejected'));
$workflow->setMetadata([
'title' => '我的审批流程',
'description' => '自定义审批工作流',
'initial_place' => 'draft',
]);
return [$workflow];
}
}
namespace plugin\myplugin;
use app\common\facade\Workflow;
class BootServiceProvider
{
public function boot(): void
{
// 注册工作流
$definitions = Plugin::getWorkflowDefinitions();
foreach ($definitions as $workflow) {
Workflow::register($workflow);
}
// 监听工作流事件
\think\facade\Event::listen('workflow.after_transition', function ($params) {
if ($params['workflow']->getName() === 'my_approval') {
// 自定义逻辑:发送通知、更新数据等
}
});
}
}
namespace plugin\myplugin\controller;
use app\common\controller\BaseController;
use app\common\facade\Workflow;
class ApprovalController extends BaseController
{
/**
* 提交审批
*/
public function submit()
{
$id = $this->request->param('id');
$record = MyModel::find($id);
if (!$record) {
return $this->error('记录不存在');
}
try {
// 检查权限
if (!Workflow::can('my_approval', $record, 'submit')) {
return $this->error('当前状态不允许提交');
}
// 执行转换
Workflow::apply('my_approval', $record, 'submit', [
'user_id' => session('admin_id'),
]);
return $this->success('提交成功');
} catch (\Exception $e) {
return $this->error($e->getMessage());
}
}
/**
* 获取审批详情(含可用操作)
*/
public function detail()
{
$id = $this->request->param('id');
$record = MyModel::find($id);
// 获取当前状态和可用操作
$marking = Workflow::marking('my_approval', $record);
$transitions = Workflow::transitions('my_approval', $record);
$history = Workflow::history('my_approval', $record, 10);
$availableActions = [];
foreach ($transitions as $trans) {
$availableActions[] = [
'name' => $trans->getName(),
'label' => $trans->getName(), // 可从 metadata 获取显示名称
'can' => Workflow::can('my_approval', $record, $trans->getName()),
];
}
return $this->success('获取成功', [
'record' => $record,
'current_place' => $marking,
'available_actions' => $availableActions,
'history' => $history,
]);
}
}
use wise\workflow\MarkingStoreInterface;
use wise\workflow\Workflow;
class RedisMarkingStore implements MarkingStoreInterface
{
protected $redis;
public function __construct($redis)
{
$this->redis = $redis;
}
public function getMarking(string $subject): array
{
$data = $this->redis->get('workflow:marking:' . $subject);
return $data ? json_decode($data, true) : [];
}
public function setMarking(string $subject, array $marking, array $context = []): void
{
$this->redis->set('workflow:marking:' . $subject, json_encode($marking));
}
public function recordHistory(string $subject, string $transitionName, string $fromPlace, string $toPlace, array $context = []): void
{
// 历史记录仍可写入数据库或 Redis List
}
}
// 在 ServiceProvider 中替换绑定
$this->app->bind(MarkingStoreInterface::class, function () {
return new RedisMarkingStore(redis());
});
// 条件守卫:根据业务数据判断
$transition = new Transition(
'auto_approve',
'reviewing',
'approved',
function ($marking, $context) {
// 金额小于 1000 的订单自动通过
if (isset($context['amount']) && $context['amount'] < 1000) {
return true;
}
// 否则需要手动审批权限
return PermissionService::check('order.approve');
}
);
// 方式一:直接插入数据库
\think\facade\Db::name('workflow_definition')->insert([
'name' => 'order_approval',
'title' => '订单审批流程',
'description' => '标准订单审批工作流',
'places' => json_encode(['draft', 'submitted', 'reviewing', 'approved', 'rejected']),
'transitions' => json_encode([
['name' => 'submit', 'from' => ['draft'], 'to' => ['submitted']],
['name' => 'assign', 'from' => ['submitted'], 'to' => ['reviewing']],
['name' => 'approve', 'from' => ['reviewing'], 'to' => ['approved']],
['name' => 'reject', 'from' => ['reviewing'], 'to' => ['rejected']],
]),
'initial_place' => 'draft',
'status' => 1,
'create_time' => date('Y-m-d H:i:s'),
'update_time' => date('Y-m-d H:i:s'),
]);
// 方式二:通过 Facade 注册(动态创建定义)
$workflow = (new Workflow('my_approval'))
->addPlace(new Place('draft'))
->addPlace(new Place('approved'))
->addTransition(new Transition('approve', 'draft', 'approved'));
$workflow->setMetadata([
'title' => '我的审批流',
'description' => '测试',
'initial_place' => 'draft',
]);
Workflow::register($workflow);
// 监听 after_transition 事件同步更新业务表
Event::listen('workflow.after_transition', function ($params) {
$subject = $params['subject'];
$newPlaces = $params['workflow']->getPlaces(); // 结合 marking 获取当前状态
// 更新业务表的状态字段
$orderId = str_replace('order:', '', $subject);
\think\facade\Db::name('orders')
->where('id', $orderId)
->update(['wf_status' => implode(',', array_keys($newPlaces))]);
});
// 使用 Facade
if (Workflow::is('order_approval', $order, 'draft')) {
echo '当前为草稿状态';
}
// 使用引擎
$marking = $engine->getMarking('order:1001');
if (isset($marking['draft'])) {
echo '当前为草稿状态';
}
$transitions = Workflow::transitions('order_approval', $order);
foreach ($transitions as $transition) {
echo $transition->getName(); // submit, approve, reject...
}
$transition = new Transition('approve', 'reviewing', 'approved', function ($marking, $context) {
// 自定义权限逻辑
return $context['user_role'] === 'manager' && $context['amount'] < 10000;
});
$engine->init($approvalWorkflow, 'order:1001'); // 审批工作流
$engine->init($paymentWorkflow, 'order:1001'); // 支付工作流(共享同一 subject)
// 从已通过回退到审核中
$workflow->addTransition(new Transition('rollback', 'approved', 'reviewing'));
// 在 database.php 中配置
'connections' => [
'mysql' => [
'prefix' => 'ws_', // 表前缀,如 ws_workflow_marking
],
],
bash
# 第一步:复制迁移文件到框架的 database/migrations/ 目录
php think wise:workflow:publish
# 第二步:执行迁移创建数据库表
php think migrate:run
plugins/workflowdemo/
├── Plugin.php # 插件主类(工作流定义)
├── manifest.json # 插件清单(菜单+权限定义)
├── BootServiceProvider.php # 启动服务提供者(注册工作流+事件)
├── controller/
│ ├── Base.php # 控制器基类
│ └── Order.php # 订单控制器(工作流操作)
├── model/
│ └── WorkflowOrder.php # 订单模型
├── route/
│ └── plugin.php # 后端路由
├── database/migrations/
│ └── 20260606000001_create_workflow_orders_table.php
└── view/order/
├── index.html # 订单列表页
├── form.html # 订单创建/编辑页
└── detail.html # 订单详情页(工作流操作按钮)
bash
# 工作流初始化:发布配置文件和迁移文件到框架对应目录
php think wise:workflow:publish
# 然后执行 ThinkPHP 系统迁移命令创建数据库表
php think migrate:run