davidsteinsland / cakephp-state-machine
该软件包已被废弃且不再维护。未建议替代软件包。
CakePHP的StateMachineBehavior
1.1
2013-10-03 12:19 UTC
Requires
- php: >=5.3.0
- composer/installers: *
Requires (Dev)
- satooshi/php-coveralls: dev-master
This package is not auto-updated.
Last update: 2017-07-01 09:31:47 UTC
README
文档尚未完成。如果您想了解一些内容,请查看测试,因为所有状态机的方面都在那里进行了测试。
什么是状态机?
http://en.wikipedia.org/wiki/State_machine
安装
首先,您需要修改您想要使用StateMachine的模型的表
ALTER TABLE `vehicle` ADD `state` VARCHAR(50); ALTER TABLE `vehicle` ADD `previous_state` VARCHAR(50);
功能
- 状态和转换上的回调
- 可以为您模型添加自定义方法
is($state)
、can($transition)
、on($transition, 'before|after', callback)
和when($state, callback)
方法允许您控制整个流程。使用transition($transition)
在两个状态之间移动。- 角色和规则
- Graphviz
回调
您可以在转换之前/之后、状态更改之前/之后添加回调。这可以通过 $this->on('mytransition', 'before', funtion() {})
手动完成,或者您可以在模型中添加一个方法
public function onBeforeTransition($currentState, $previousState, $transition) { // will fire on all transitions } public function onAfterIgnite($currentState, $previousState, $transition) { // will fire after the ignite transition }
状态回调略有不同
public function onStateChange($newState) { // will fire on all state changes } public function onStateIdling($newState) { // will fire on the idling state }
命名约定
-
在
$transitions
中的转换和状态应该是 小写 和 下划线。方法名称随后采用驼峰式。示例
shift_up => canShiftUp() => shiftUp()
first_gear => isFirstGear()
如何使用
App::uses('StateMachineBehavior', 'StateMachine.Model/Behavior'); class VehicleModel extends AppModel { public $useTable = 'Vehicle'; public $actsAs = array('StateMachine.StateMachine'); public $initialState = 'parked'; public $transitionRules = array( 'ignite' => array( 'role' => array('driver'), 'depends' => 'has_key' ) ); 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' ) ); public function __construct($id = false, $ds = false, $table = false) { parent::__construct($id, $ds, $table); $this->on('ignite', 'after', function($prevState, $nextState, $transition) { // the car just ignited! }); } // a shortcut method for checking if the vehicle is moving public function isMoving() { return in_array($this->getCurrentState(), array('first_gear', 'second_gear', 'third_gear')); } // the dependant function for "ignite" public function hasKey($role) { return $role == 'driver'; } }
使用上述模型,我们有以下方法
isParked() onStateParked()
isStalled() onStateStalled()
ignite() canIgnite() onBeforeIgnite() onAfterIgnite()
park() canPark() onBeforePark() onAfterPark()
isFirstGear() onStateFirstGear()
shiftUp() canShiftUp() onBeforeShiftUp() onAfterShiftUp()
....
class Controller .... { public function method() { $this->Vehicle->create(); $this->Vehicle->save(array( 'Vehicle' => array( 'title' => 'Toybota' ) )); // $this->Vehicle->getCurrentState() == 'parked' if ($this->Vehicle->canIgnite('driver')) { $this->Vehicle->ignite('driver'); $this->Vehicle->shiftUp(); // $this->Vehicle->getCurrentState() == 'first_gear' } } }
Graphviz
如果您将以下状态机保存到 fsm.gv
并运行,则Vehicle的状态机将如下所示:
$model->toDot()
运行
dot -Tpng -ofsm.png fsm.gv