libriciel/cakephp-state-machine

CakePHP 3 的 StateMachineBehavior

3.1.0 2020-10-21 15:13 UTC

README

Build Status Coverage Status Scrutinizer Quality Score Latest Stable Version Total Downloads

文档尚未完成。如果您想了解某些内容,请查看测试,因为那里测试了状态机的所有方面。

什么是状态机?

http://en.wikipedia.org/wiki/State_machine

安装

首先,您需要更改您想使用 StateMachine 的模型的表

ALTER TABLE `vehicles` ADD `state` VARCHAR(50);
ALTER TABLE `vehicles` ADD `previous_state` VARCHAR(50);

特性

  • 在状态和转换上调用回调
  • 可以添加自定义方法到您的模型中
  • is($entity, $state)can($entity, $transition)on($transition, 'before|after', callback)when($state, callback) 方法允许您控制整个流程。transition($entity, $transition) 用于在两个状态之间移动。
  • Graphviz
  • (已移除:角色和规则,欢迎提交)

回调

您可以为转换之前/之后和状态更改之前/之后添加回调。这可以通过使用 $this->on('mytransition', 'before', function() {}) 手动完成,或者您可以在模型中添加一个方法

public function onBeforeTransition($entity, $currentState, $previousState, $transition) {
    // will fire on all transitions
}

public function onAfterIgnite($entity, $currentState, $previousState, $transition) {
    // will fire after the ignite transition
}

状态回调略有不同

public function onStateChange($entity, $newState) {
    // will fire on all state changes
}

public function onStateIdling($entity, $newState) {
    // will fire on the idling state
}

命名规范

  • $transitions 中的转换和状态应该是 小写下划线分隔 的。方法名称则是驼峰式。

    示例

    shift_up   => can($entity, 'ShiftUp') => transition($entity, 'ShiftUp')
    first_gear => is($entity, 'FirstGear')

如何使用

namespace App\Model\Table;

use Cake\ORM\Table;
use Cake\ORM\Entity;

class VehiclesTable extends Table
{
    public function initialize(array $config)
    {
        $this->addBehavior('StateMachine.StateMachine');
        $this->on('ignite', 'after', function(Entity $entity, $prevState, $nextState, $transition) {
            // the car just ignited!
        });
    }

    public $initialState = 'parked';

    public $transitions = array(
            'ignite' => array(
                    'parked' => 'idling',
                    'stalled' => 'stalled'
            ),
            'park' => array(
                    'idling' => 'parked',
                    'first_gear' => 'parked'
            ),
            'shift_up' => array(
                    'idling' => 'first_gear',
                    'first_gear' => 'second_gear',
                    'second_gear' => 'third_gear'
            ),
            'shift_down' => array(
                    'first_gear' => 'idling',
                    'second_gear' => 'first_gear',
                    'third_gear' => 'second_gear'
            ),
            'crash' => array(
                    'first_gear' => 'stalled',
                    'second_gear' => 'stalled',
                    'third_gear' => 'stalled'
            ),
            'repair' => array(
                    'stalled' => 'parked'
            ),
            'idle' => array(
                    'first_gear' => 'idling'
            ),
            'turn_off' => array(
                    'all' => 'parked'
            )
    );

    // a shortcut method for checking if the vehicle is moving
    public function isMoving(Entity $entity) {
        return in_array($this->getCurrentState($entity), array('first_gear', 'second_gear', 'third_gear'));
    }

}
class Controller .... {
    public function method() {
        $this->loadModel('Vehicles');
        $entity = $this->Vehicles->newEntity();
        $entity->title = 'Toybota';
        $this->Vehicles->save($entity);

        // $this->Vehicles->getCurrentState($entity) == 'parked'
	if ($this->Vehicles->can($entity, 'Ignite')) {
       	 	$this->Vehicles->transition($entity, 'Ignite');
       	 	$this->Vehicles->transition($entity, 'shiftUp');
        	// $this->Vehicles->getCurrentState($entity) == 'first_gear'
        }
    }
}

Graphviz

以下是如何将车辆的有限状态机保存为

$table->toDot()

fsm.gv 并运行

dot -Tpng -ofsm.png fsm.gv