timatanga/workflow

timatanga Workflow 包。管理类/对象的工作流状态

v0.1.0 2021-09-29 17:51 UTC

This package is auto-updated.

Last update: 2024-09-29 05:56:55 UTC


README

Workflow 模块提供管理工作流的功能。此包主要受 Symfony Workflow 组件的启发,并增加了一些特定扩展,例如

  • 如果通过事件来保护转换,则条件回调允许有更多控制
  • 监听器允许自动转换

安装

composer require dbisapps/workflow

注册

在 Laravel 应用的 config/app.php 配置文件中,providers 选项定义了应该由 Laravel 加载的服务提供者列表。当用户安装您的包时,您通常会希望您的服务提供者被包含在这个列表中。为了不要求用户手动将服务提供者添加到列表中,此包通过自动发现来启用这一功能。

类/对象配置

要启用类或对象的工作流管理,需要一些配置

  • 实现 WorkflowStoreInterface

  • 使用 HasWorkflow 特性

      class Subject implements WorkflowStoreInterface
      { 
          use HasWorkflow;
      }
    

使用配置文件进行配置

对于 Laravel 应用,可以使用 config/workflow.php 来提供工作流配置。请参考 tests 目录下的 Config.php,以获取工作流配置示例。

然后将配置文件的路径传递给注册类构造函数。

	$registry = new Registry(config_path('workflow.php'));

不使用配置文件进行配置

可以在没有配置文件的情况下构建工作流注册

	// create registry instance
    $registry = new Registry;

    // create event dispatcher which is optional but required for events, listeners
    $dispatcher = new EventDispatcher;

    // build transitions
    $transitions = [];
    $transitions[] = new Transition('t1', 'a', 'b');
    $transitions[] = new Transition('t2', 'b', 'c');

    // build workflow definition
    $definition = new Definition([
        'name' => 'workflow name', 
        'states' => range('a', 'c'),
        'initial' => 'a',
        'transitions' => $transitions, 
    ]);

    // add workflow and its supported class/object to registry
    $registry->addWorkflow(new Workflow($definition, $dispatcher), Subject::class);

基本用法

	// retrieve workflow for subject by accessing registry. 
	$workflow = $registry->get(new Subject());

	// when more than one workflow is assigned to subject, the specific workflow must be named 
	$workflow = $registry->get(new Subject(), 'workflow name');

	// retrieve array of enabled transitions, that are applicable on current state and conditions
	$transitions = $workflow->enabledTransitions($subject);

	// retrieve array of blocked transitions as TransitionBlocker 
	$blocked = $workflow->blockedTransitions($subject);

	// evaluate if transition is allowed on subjects current state
	$can = $workflow->can($subject, 't2')

	// apply a transition on subject, supress events (optional). New state/states are returned
	$state = $workflow->apply($subject, 't2', [Workflow::LEAVE])

转换事件

在转换前后都会触发多个事件。应用事件调度器后,可以挂钩到这些事件:离开 > 转换 > 进入 > (更改状态) > 进入。状态在进入后和进入前更改。

可以限制已分发的事件

在工作流配置文件中

	return [
	    'workflow name' => [
	        'supports' => Subject::class,
	        ...
	        'events' => [Workflow::ENTER_LEAVE, Workflow::ENTER_EVENT],
	]

在工作流定义中

    return new Definition([
        'name' => 'workflow name', 
        ...
        'events' => [Workfow::LEAVE_EVENT, Workflow::ENTERED]
    ]);

在应用转换时

	$state = $workflow->apply($subject, 't2', [Workfow::LEAVE_EVENT, Workflow::ENTERED])

转换条件

如果将条件分配给转换,则必须在转换允许触发之前满足所有条件。条件可以在工作流配置中预先配置或在运行时配置。

	// build a condition
    $fn = new Condition('blocked', function($subject) { return $subject->blocked == false; });

    // extend a workflow transition with additional condition
    $workflow->extend('t2', $fn );

    // remove condition from transition
    $workflow->reduce('t2', $fn );

转换监听器

想象一下有一个发票工作流,它已经达到了最新状态。当达到最新状态时,应该启动付款工作流,并将付款实例持久化到数据库中。这个需求需要在不同工作流之间建立某种连接。

这就是转换监听器发挥作用的地方。在监听事件时,可以自动触发工作流转换。基本上,这可以在工作流内部完成,也可以在不同的工作流之间完成。

	// create a callback function 
    $cb = function($event) { $event->getWorkflow()->apply($event->getSubject(), 't2'); };

    // create a listener, when worklfow A has entered state completed, invoke callback
    $listener = new Listener('workflow.workflow_A.entered.completed', $cb);

    // configure listener in workflow definition
    $definitionB = new Definition([
        'name' => 'workflow_B', 
        ...
        'listeners' => $listener,
    ]);

    // create workflows, with shared event dispatcher 
    $eventDispatcher = new EventDispatcher;
    $workflowA = new Workflow($definitionA, $eventDispatcher);
    $workflowB = new Workflow($definitionB, $eventDispatcher);

    // apply transition t2 on subjectA
    $subjectA = new Subject();
    $states = $workflowA->apply($subjectA, 't2');

    // the result of the listener callback can be accessed by listener method
	// in this case, a new subject has been created
    $subjectB = $listener->result();

上下文模型

                           					  ----------			   ---------
CONTROLS                   					   Condition    		   Condition
                           					  ----------    		   ---------
                                   				   v     				   v

                                 ------------            ------------            ------------                  
PROCESS               x----------    State   ------------    State   ------------    State   
                      ^           ------------     ^     ------------      ^     ------------           
					  |							   |					   |
					  							   |					   |
TRANSITION 			  							   O					   O	
					  
					  |
					  |
LISTENER 			  O
                       
					  ^							   ^					   ^
                  ----------				  ----------			  ----------
RESOURCE            Subject					    Subject 			    Subject
                  ----------				  ----------			  ----------



Registry		Workflows must be assigned to supported classes/objects. These assignments are stored
				in the workflow registry.

Workflow		A workflow manages transitions between states of a supported class/object. It therefor
				contains workflow definitions and capabilities like event dispatcher or logger.

Definition 		Workflow configurations are provides as definitions, like
				- name	    	workflow name
				- states    	states of the workflow
				- initial   	initial state of the workflow
				- transitions   transitions between states
				- events 		events to dispatch, null to dispatch all events
				- listeners     listeners to automate transitions

State 			State of a workflow. A state is also called as place.

Transition 		A Transitions defines the source (froms) and destination (tos) states.
				In case of multiple source destinations all must be met before a transition can be applied.
				Multiple destination states are allowed to be transitioned at once,

Conditions		Conditions are logical rules (boolean) which must be fulfilled before a transition can take place.
				A condition normaly is related to its subject attributes.

Listener 		Listeners extend workflow capabilites to allow for automated transitions.
				State changes are firing events and can trigger subsequent transitions without user interactions.