eftec / statemachineone
适用于业务流程的状态机库
Requires
- php: >=7.4
- ext-ctype: *
- ext-json: *
- eftec/documentstoreone: ^1.27
- eftec/minilang: ^2.28
- eftec/pdoone: ^4.8
Requires (Dev)
- phpunit/phpunit: ^9.0
README
这是一个专门针对业务流程编写的PHP状态机库。
该库只有一个简单的外部依赖,是一个最小化(但完整)的库,仅包含3个类。
由于这个库是PHP原生,所以它可以在Laravel、Symfony以及其他任何框架中运行。
什么是状态机?
状态机(也称为 自动机)是基于 状态 的 作业 的程序执行。每个作业在同一时间必须有一个单一的状态,例如“已启动”、“待处理”、“进行中”等,作业根据某些逻辑或条件改变状态(转换)。这些条件可以是字段、时间或自定义函数。
该库的目标是简化创建业务状态机的流程。
目录
注意
- 作业:它是运行的过程。作业在同一时间可以只有一个状态。
- 状态:它是作业的当前条件。
- 转换:它是从一个 状态 到另一个状态的转换。转换受一组值、时间或函数的限制。
此外,每个转换都可以有超时。如果达到超时,则执行转换,无论值或条件如何(即使有活动的状态暂停)。转换可以有3种结果- 改变 转换改变状态,作业保持活跃。只有当作业有活动的状态 = 活跃时,才能执行转换。
- 暂停 转换改变状态,作业暂停。只有当作业有活动的状态 = 活跃时,才能执行转换。
- 继续 转换改变状态,作业从暂停中恢复。只有当作业有活动的状态 = 暂停或活跃时,才能执行转换。
- 停止 转换改变状态,作业停止。只有当作业有活动的状态 = 活跃或暂停时,才能执行转换。
- 停留 转换不改变状态,但执行由集合定义的操作。
- 停留一次 它与停留类似,但只执行一次操作。
- 事件:(可选)。事件是特殊操作,可以改变一个或多个状态。
- 活跃状态:每个任务都有一个活跃状态。共有4种:无、停止、活跃、非活跃、暂停。它不同于状态。例如,一个任务可能的状态是:进行中,而活跃状态是:暂停。
- 无 = 任务不存在。它不能改变状态,也不能默认加载(从数据库中)。
- 停止 = 任务已停止(完成),可能是成功、中止或取消。它不能改变状态,也不能默认加载。
- 暂停 = 任务处于暂停状态,它不会改变状态(除非被强制),但可以继续。
- 活跃 = 任务正常运行,它可以改变状态。
- 非活跃 = 任务计划在某个日期运行。除非激活(由计划),否则不能改变状态。
- 参考:每个任务都有一些相关字段。例如,如果任务是关于发票的,那么参考必须是发票编号。状态机不使用任何参考,但它保留这些值以与其他系统集成。
- 字段:每个任务都有一些字段或值,它可以触发转换。
例如,ChopSuey中国外卖食品。
我们需要创建一个过程来提供送餐服务。这容易吗?好吧,让我们来看看。
字段(ChopSuey练习)
字段是用于状态机的值。在这个例子中,我没有包括其他可能有用的值(如金钱、客户姓名、地址等),因为它们不是状态机的一部分或未被使用。
- customerpresent = 1 如果客户在家,0 = 如果不在,= null 如果尚未定义。
- addressnotfound = 1 如果配送员找不到地址,= 0 如果找到,= null 如果尚未定义。
- signeddeliver = 1 如果客户签收了配送,= 0 如果没有,= null 如果未定义。
- abort = 1 如果配送必须中止(例如,发生事故),= 0 如果不是。
- instock = 1 如果产品有库存,= 0 如果没有,= null 如果未定义。
- picked = 1 如果配送员已经取货并打包产品,= 0 如果还没有。
状态(ChopSuey练习)
必须包含所有可能的情况。现实世界并不像:销售和金钱那么简单。
- STATE_PICK 配送员将取任何食物。例如,如果客户点了北京烤鸭(带橙酱)而餐馆没有怎么办?
- STATE_CANCEL 订单被取消。
- STATE_TRANSPORT 配送员正在路上送食物。
- STATE_ABORTTRANSPORT 发生了一些事情,配送必须中止。
- STATE_HELP 配送员准备好送餐,但他找不到地址或可能没有人,所以他呼叫求助。
- STATE_DELIVERED 食物已送达。我们的英雄返回基地(中国餐馆)。
- STATE_ABORTED 交易被中止,无人在家或地址错误。
转换(ChopSuey练习)
- STATE_PICK -> STATE_CANCEL (END) 当?instock=0(任务结束)
- STATE_PICK -> STATE_TRANSPORT 当?instock=1 和 picked=1
- STATE_TRANSPORT -> STATE_ABORTTRANSPORT (END) 当?abort=1(由于某种原因,我们的男孩中止了运输,是不是下雨了?)
- STATE_TRANSPORT -> STATE_DELIVERED (END) 当?addressnotfound=0,customerpresent=1 和 signeddeliver=1。它已送达,客户在场,并签收了配送(希望还能得到小费)
- STATE_TRANSPORT -> STATE_HELP 当?addressnotfound=1,customerpresent=0 和 signeddeliver≠1。我们的配送员打电话回家寻求新的指示。是不是假的街道1234这个地址正确?。
- STATE_HELP -> STATE_ABORTED (结束) 何时?(15分钟期限)或如果abort=1。
我们的送货上门,是的,地址是假的(这是一个令人震惊的惊喜) - STATE_HELP -> STATE_DELIVERED (结束) 何时?addressnotfound=0,customerpresent=1和signeddeliver=1。已经送达,客户在场,并已签收(希望还有小费)
最终代码(ChopSuey示例)
其他示例
示例/BuyMilk.php(购买牛奶)
示例/Car.php(汽车停车)
<?php use eftec\statemachineone\StateMachineOne; include "vendor/autoload.php"; define("STATE_PICK",1); define("STATE_CANCEL",2); define("STATE_TRANSPORT",3); define("STATE_ABORTTRANSPORT",4); define("STATE_TODELIVER",5); define("STATE_HELP",6); define("STATE_DELIVERED",7); define("STATE_ABORTED",8); $smachine=new StateMachineOne(); $smachine->setDebug(true); $smachine->tableJobs="chopsuey_jobs"; $smachine->tableJobLogs="chopsuey_logs"; $smachine->setDefaultInitState(STATE_PICK); $smachine->setAutoGarbage(false); // we don't want to delete automatically a stopped job. $smachine->setStates([STATE_PICK=>'Pick order' ,STATE_CANCEL=>'Cancel order' ,STATE_TRANSPORT=>'Transport order' ,STATE_ABORTTRANSPORT=>'Abort the delivery' ,STATE_TODELIVER=>'Pending to deliver' ,STATE_HELP=>'Request assistance' ,STATE_DELIVERED=>'Delivered' ,STATE_ABORTED=>'Aborted']); $smachine->fieldDefault=[ 'customerpresent'=>-1 ,'addressnotfound'=>-1 ,'signeddeliver'=>-1 ,'abort'=>-1 ,'instock'=>-1 ,'picked'=>-1 ,'message'=>'']; $smachine->setDB('mysql','localhost',"root","abc.123","statemachinedb"); $smachine->createDbTable(false); // you don't need to create this table every time. $smachine->loadDBAllJob(); // we load all jobs, including finished ones. // business rules $smachine->addTransition(STATE_PICK,STATE_PICK ,'when instock = 0 set message="without stock"','stay'); // it stays in the same state $smachine->addTransition(STATE_PICK,STATE_CANCEL ,'when instock = 0 set abort = 1','stop'); // ends the process $smachine->addTransition(STATE_PICK,STATE_TRANSPORT ,'when instock = 1','change'); // changes transition $smachine->addTransition(STATE_TRANSPORT,STATE_ABORTTRANSPORT ,'when abort = 1','stop'); // ends the process $smachine->addTransition(STATE_TRANSPORT,STATE_DELIVERED ,'when addressnotfound = 0 and customerpresent = 1 and signeddeliver = 1 timeout 3600','stop'); // 1 hour max. $smachine->addTransition(STATE_TRANSPORT,STATE_HELP ,'when addressnotfound = 1 or customerpresent = 0 timeout 3600','change'); // 1 hour max $smachine->addTransition(STATE_HELP,STATE_ABORTED ,'when wait timeout 900','change'); // it waits 15 minutes max. $smachine->addTransition(STATE_HELP,STATE_DELIVERED ,'when addressnotfound = 0 and customerpresent = 1 and signeddeliver = 1','change'); $msg=$smachine->fetchUI(); $smachine->checkAllJobs(); $smachine->viewUI(null,$msg); // null means it takes the current job
转换语言
假设下一个转换
$smachine->addTransition(STATE_PICK,STATE_CANCEL ,'when instock = 0 set abort = 1','stop');
转换被写成如下
- 初始状态(或初始状态)
- 结束状态
- 转换语言
- 结果,可能是 change(默认值)stop,pause, continue 和 stay
- change 意味着如果满足条件(或超时),状态将从 初始状态 变更到 结束状态。只有在状态活动时才会进行变更。
- stop 意味着状态将变更并且工作将停止(工作结束)
- pause 意味着状态将变更并且工作将暂停。一个暂停的工作不能变更状态,即使它满足条件。
- continue 意味着状态将变更并且工作将从暂停处继续。
- stay 意味着状态不会变更(但如果有的话,将执行任何其他指令)。
转换语言使用以下语法编写。
"_when_ var1 = var2 and var3 = var4 or var4 = var5" "_set_ var1 = var2 , var3 = var4" "_timeout_ var1" "_fulltimeout_ var2"
- 我们可以在 when 和/或 set 和/或 else 中执行三个操作
转换当
它添加了一个条件,表示转换必须执行的位置。例如
$smachine->addTransition(STATE_ONE,STATE_TWO,'when field = 0');
在这种情况下,当字段为零时,状态从 STATE_ONE 变更到 STATE_TWO。
也可以存在多个初始状态
$smachine->addTransition([STATE_ONE,STATE_EXTRA],STATE_TWO,'when field = 0'); // its the same than to add multiples transitions: // $smachine->addTransition(STATE_ONE,STATE_TWO,'when field = 0'); // $smachine->addTransition(STATE_EXTRA,STATE_TWO,'when field = 0');
转换类型
"when field=0" // it happens when the field is zero. "when $var='hi'" // it happens when the global variable is 'hi' "when fn()=44" // the transition is triggered when the function fn() returns 44 "when always" // its always true. It is the same than "when 1=1". The transition is always executed
它比较一个常量。比较的二进制运算符是
- = 等于
- <> 不等于
- < <= “小于”和“小于等于”
- > >= “大于”和“大于等于”
- contain 如果一个文本包含其他文本。
"when field contain 'text'"
字段的值可以是以下之一
- field = 它是作业的字段。
"when field = field2" // when field (of the job) is equals to field2
- _idjob = 它是当前作业的编号。每次评估作业时都会计算。
"set id=_idjob"
- _time = 它是当前时间戳。每次评估作业时都会计算。注意:它使用getTime()函数,并且可以修改。
"set ts=_time"
- _state0 = 它是作业的初始(当前)状态(作为状态的ID)
"set currentstate=_state0"
- _state1 = 它是作业的下一个状态(作为ID)。仅在作业状态转换时评估,否则为null。不能在“when”中使用,因为转换尚未发生。
"set nextstate=_state1"
- _result = 它是转换的结果('change','pause','continue','stop','stay','stayonce')。仅在作业状态转换时评估,否则为null。不能在“when”中使用,因为转换尚未发生。
"set transition_happened=_result"
- $var = 它是PHP的全局变量。请注意
$v1=20; $smachine->addTransition(S1,S2,"when $v1=1"); // WRONG: the variable v1 is evaluated when it is defined, i.e equals to write "when 20=1" $smachine->addTransition(S1,S2,"when \$v1=1"); // RIGHT: the variable v1 is evaluated when the transition is checked $smachine->addTransition(S1,S2,'when $v1=1'); // RIGHT:(') the variable v1 is evaluated when the transition is checked
- 777 = 它是一个数字常量
"when field = 777" // when field is equals to 777
-
"AAA",'aaa' = 它是一个文本
当field = 'hello' // 当字段等于文本hello时 -
function() = 它是一个全局函数。每个函数都必须有$job参数。
"when field = somefunc()" // function somefunc(Job $job) {...}
- null() 它是空值
"when field = null() "
- true() 它是真值(true)
"when field = true()" // when field is equals to true
- false() 它是假值(false)
"when field = true()" // when field is equals to false
on() 它是开值(1)
off() 它是关值(0)
undef() 它是未定义值(-1)
flip() 表示值将被反转(1=>0和0=>1)。例如(x=1)x = flip(),现在(x=0)。如果值不为零,则将其反转为零。
"set field=flip()" // it is only valid for set.
- now() 定义当前时间戳(以秒为单位)。
- interval() 返回当前状态与上次状态之间的间隔。
- fullinterval() 返回当前状态与作业开始之间的间隔。
- timestate() 返回当前状态的时间流逝。
例如
$smachine=new StateMachineOne(); function someFunction($job) { // we could do something here we should return a value return 0; } $var=222; $smachine->fieldDefault=[ 'field2'=>0 ,'field3'=>0 ,'field4'=>0]; $smachine->addTransition(STATE_ONE,STATE_TWO ,'when field2 = 2 and field3 > someFunction() and field4=$var');
转换设置
在状态转换时,我们可以添加一个或多个变量变化。
$smachine->addTransition(STATE_ONE,STATE_TWO,'when field = 0 set field=1');
在这种情况下,当我们处于 "STATE_ONE" 状态且 field=0 时,我们转换为状态 "STATE_TWO",并将 field=1 赋值。
示例
"set field = 0 , field2 = 3"
它设置作业的字段。
- 操作的第一个值不能是常数。
"set 0 = 20" // is invalid
- 我们也可以设置一个函数。
"set myfunc() = 20"
其中函数(全局)必须定义为 myfunc(Job $job,$input) {}
- 第一个值可以是字段或(全局)变量。
"set field=20" "set $variable=20" "set field = 0"
它将字段设置为 0。
"set field + 1"
它将字段的值增加 1(field=field+1)。
"set field - 1"
它将字段的值减少 1(field=field-1)。
转换否则
它与 "set" 类似,但它在状态转换未完成时执行。
$smachine->addTransition(STATE_ONE,STATE_TWO,'when field = 0 set field2="done" else field2="not done"');
在这种情况下,它将 field2="未完成" 设置为状态转换完成之前。
注意:此操作在每次表达式评估时都会调用。因此,它可能被评估多次。
转换超时(秒)
$smachine->addTransition(STATE_ONE,STATE_TWO,'when field = 0 timeout 3600');
当字段为零或状态 ONE 中的 3600 秒已过时,状态从 STATE_ONE 转换到 STATE_TWO。
它设置当前状态和当前时间之间的超时时间。如果发生超时,则执行转换。
"timeout 3600" // 1 hour timeout "timeout field" // timeout by field, it is calculated each time.
转换完全超时(秒)
$smachine->addTransition(STATE_ONE,STATE_TWO,'when field = 0 fulltimeout 3600');
当字段为零或自作业开始以来已过 3600 秒时,状态从 STATE_ONE 转换到 STATE_TWO。
它设置初始状态和当前时间之间的超时时间。如果发生超时,则执行转换。
"fulltimeout 3600" // 1 hour timeout "fulltimeout field" // timeout by field, the field is evaluated each time.
JOB
什么是作业?
假设我们有一个蓝图来建造房屋。这里的 job 是建造房屋的动作,而蓝图是 transitions。
因此,作业是我们工作流程的一个操作部分。
一个 job 保存值,包括当前 state,并且它有一个生命周期,而工作流程(转换)不保存任何单个值。我们可以创建一个短生命周期作业,它在单个网络线程中工作。然而,如果我们需要保存值,则可以使用数据库或文件系统(平面文件)。
创建作业
有几种创建作业的方法。其中之一是使用 GUI,另一种是通过代码。
通过代码创建作业
// $smachine is our state machine with transitions, events and such. $job=$smachine->createJob(['value1'=>'hi','value2'=>'world']); // we create a job with the values value1 and value2 // or we could create the job the with the default values $job=$smachine->createJob(); $smachine->checkJob($job); // then we executed the job. var_dump($job->state); // the id of the current state. var_dump($job->fields); // And we could see the result of the job
在作业中运行状态机
$smachine->checkJob($job); // then we executed the job. $smachine->checkAllJob(); // We execute all jobs stored in our state machine.
获取作业
$smachine->getLastJob(); // we load the last job (if we already has a job into a memory); $smachine->getJob($idJob); // we get a job from the queue. $smachine->getJob($idJob); // we get a job from the queue. $smachine->getJobQueue(); // we get all the jobs from the queue $smachine->loadDbJob($idJob); // we read a job with the id $idJob and we store into the queue $smachine->loadDbAllJob(); // We load all jobs (including inactive jobs) from the database and we store into the queue $smachine->loadDBActiveJobs(); // We load all active jobs from the database and we store into the queue.
数据库和作业。
$smachine->loadDbJob($idJob); // we read a job with the id $idJob $smachine->loadDbAllJob(); // We load all jobs (including inactive jobs) from the database. $smachine->loadDBActiveJobs(); // We load all active jobs from the database. $smachine->saveDBAllJob(); // we save all the jobs in memory. $smachine->saveDBJob($job); // we save a specific job. $smachine->saveDBJobLog($job,$texto); // we save a log of a job. $smachine->deleteJobDB($job); // we delete a specific job.
作业中使用的字段
- $idJob int 作业在队列中的编号或位置
- $idParentJob int|null 父作业的编号
- $dateInit int 初始日期(时间戳)
- $dateLastChange int 最后更改的日期(时间戳)
- $dateEnd int 结束日期(时间戳)
- $dateExpired int 过期日期(时间戳)
- $state string|int 当前状态的 ID
- $fields array 每个作业的字段或值。它必须是一个关联数组
- $stateFlow array 指示状态流
- $transitions bool[] 用于确定转换是否已执行
- $isNew bool 如果作业是新作业。用于存储到数据库中(插入)
- $isUpdate bool 如果作业已更新。用于存储到数据库中(更新)
- $log string[]
标志
可以在作业中存储一个或多个标志。
标志是一个状态或值,
- 它可以有名称。
- 它可以有一个级别,例如严重程度级别。
- 它可以有一个过期时间。
- 可以有一个可交换的值,例如开关。
- 它与 StateMachineOne 实例和作业相关联。
创建标志数组的示例
$flags=new Flags('flag1', true, $smachine); // the flags is called flag1, $smachine is a state machine $flags->setParent($job); // it is also associate with a job.
图形用户界面
此库具有内置的 GUI 用于测试。
类
StateMachineOne 这是主类。Job 这是作业的模型类。
Transition 这是转换的模型类。
缓存配置
可以缓存所有配置。
保存配置
$stateMachine=new StateMachineOne(); // configuration goes here. file_put_contents("mycode.php", "<?php\n".$stateMachine->cacheMachine("FumMachineCache"));
加载配置
$stateMachine=new StateMachineOne(); include 'mycode.php'; FumMachineCache($stateMachine);
日志格式
通常,日志格式可以是 info 或 error 类型。标志可以显示不同类型。
[info]
state,,changed,,Parked,,1,,Idling,,2,,0,,change
-
state = 操作的动词。
-
changed = 执行的操作。可以是 changed,stop,continue。
-
Parked = 第一个状态(在变化之前)
-
1 = 第一个状态的编号(在变化之前)
-
Idling = 它变化到的状态。
-
2 = 它变化到的状态的编号。
-
0 = 触发变化的交易。
-
change = 变化的描述。
[error]
state,,transition,,text,,1,,message // 当作业的检查失败时
savejob,,message // 保存作业失败时。
changestate,,idjob,,idstate,newstate // 当状态变化失败时
许可
双许可(LGPL 3.0 和商业)。请参阅 LICENSE 文件。
版本
-
2.26 2024-07-20
- 添加了函数 setRecordEventState(),replayRecordInit() 和 replayRecordInsideLoop()
-
2.25 2024-07-19
- 添加了函数 setTime()
-
2.24 2024-07-18
- 升级到 PHP 7.4
- 更新注释
-
2.23.3 2023-06-29
- 修复了 flag::pull() 中的问题,其中 msg 为 null。
-
2.23.2 2023-06-29
- 修复了 flag::push() 中的问题,其中值为 null。
-
2.23.1 23-03-11
- 更新了依赖项。
-
2.23 22-09-11
- 为转换添加了描述(注释)。
- 修复了 GUI 中的问题(作业必须是整数)
-
2.22 22-09-11
- 添加了变量 _state0,_state1,_time,_result 并修复了 _idjob
-
2.21.1 2022-09-03
- 修复了 Flags 中 Job 或 Parent 为 null 的问题。
- 接口 StateSerializable 参数允许 Job 或 null
-
2.21 2022-09-03
- 更新了依赖项。
- 大多数方法添加了类型提示/验证。
-
2.20 2022-08-26
- 修复了一些错别字。
- 修复了 gettime() 的一个错误,它可能返回浮点数或整数。
-
2.18 2022-06-28
- 更新依赖项。
-
2.17 2021-10-01
- [核心] 添加了方法 $zeroDate,用于在数据库中设置默认的日期时间值。
-
2.17 2021-09-26
- [核心] 添加了方法 duringState2(),以便添加一个保持状态的转换,因此可以将逻辑保存到类中。
-
2.16 2021-09-26
- [核心] 更新了类 MiniLang 的依赖项 2.20.1
- [核心] 解决了方法 SaveDbJob() 的问题。
- [核心] 新方法 addMethodTransition2() 可以用于创建一个使用 MiniLang 新版本逻辑的类。
- [转换] 现在类 Transition 可以在运行时使用 Minilang(正常行为)或使用预编译生成的类来计算转换。这个特性将大大提高性能,但需要创建这个类。
-
2.15 2021-09-18
- 为类 Flag 添加了方法 messages()
-
2.14 2021-09-17
- 添加了 duringState(),允许在作业处于某些状态时执行一个操作。
- 添加了内部函数 timestate(),它返回当前状态的当前时间(当前作业的状态)。
-
2.13 2021-07-03
- addTransition() 现在允许多个初始状态。
- 在 composer.json 中更新了依赖项。
-
2.12 2021-01-16
- 对代码进行了一些清理。
- 更新了依赖项。
-
2.11 2020-10-16
- 作业有一个额外的字段称为 idParentJob。 作业表必须重建 或添加列:idparentjob int。
-
2.10.1 2020-10-15
- 在 saveDbJob 中有一个小错误,其中 $backup 字段为 null,而我们正在更新。
-
2.10 2020-10-15
- 日志现在由 ',,' 而不是 '|' 分隔。这是因为某些消息可能使用 "|"。
- 在日志状态中,我们添加了交易编号。
-
saveDbJob(): 在数据库中更新:库不会更新未更改的字段。为此,
它每次加载作业时都会创建一个备份变量,并将备份与要保存的作业进行比较。 -
2.9.2 2020-09-29 saveDbJob() 更新了主键字段。现在,它跳过更新。
-
2.9.1 2020-09-22 cacheMachine() 现在正确工作。
-
2.9 2020-09-20 标志的显示方式不同。此外,text_job 的序列化现在使用 serialize 而不是 JSON。之前的任务必须刷新,可以使用 $stateMachine->createDbTable(false); 来刷新。
-
2.8 2020-09-15 添加了 $fieldUI 字段以指定视觉组件。
-
2.7 2020-08-11 依赖项的小更新。
-
2.6 2020-04-23
- 简化了安装过程。现在“文档”不包括在安装中
-
2.5 2020-04-13
- 更新依赖项 eftec/pdoone 1.15 到 1.32.1
- 更新依赖项 etec/minilang 2.14 到 2.15
-
2.4 2019-12-26
- 服务对象现在可以在事件上工作。
- 更新库 eftec/PdoOne 到 1.15
-
2.3 2019-12-26
- Createdbtable() 方法现在设置一个有效的默认值
- 一些清理。
- Bootstrap 更新到 4.4.1。此外,它现在使用 https 而不是 http
-
2.2 2019-10-22
- 更新 eftec/MiniLang (依赖项) 从 2.9 => 2.12
- 更新 eftec/pdoone (依赖项) 从 1.11 => 1.12
- 添加依赖项/documentstoreone (依赖项) 到 1.11(允许使用文件系统作为数据库)
- 添加了新的方法 setDocOne(),getDocOne()
- 现在库允许使用 pdo(MySQL 数据库)或文件系统(documentOne)进行持久化。
- 修复了 UI 的问题(它只执行了最后一个任务)
- 添加了 UI 的更改。现在,可以查看和更改当前任务。
- 修复了创建表的问题。现在 TEXT_JOB 列始终被创建。
-
2.1 2019-08-28
- 更新 eftec/minilang 到 2.9。
- 允许在每字段中存储数组
- 如果任务的字段是对象或数组,则它将存储在 MEDIUMTEXT 字段(序列化)中
- 方法 Flags::flagexist()
- 方法 StateMachineOne::removetransition()
-
2.0 2019-08-24
- 更改了标志。推送的定义被反转。现在 push('msg','id'..) 变成 push('id','msg'..)
- 添加了设置时间的方法。
-
1.12 2019-08-16
- 更新 MiniLang
- 添加了 viewJson() 方法
- 现在如果任务为 null,事件不会崩溃。
- 删除了私有方法 CreateColTable()。
- Flag() 现在具有过期时间(可选)
-
1.11 2019-08-04 一些修复。
-
1.10 2019-08-04
- 更新到 "eftec/minilang": "^2.7"
- 解决了在 callEvent() 中如果没有任务则不会失败的问题。
- 添加了 cacheMachine() 方法以缓存结果。
- 代码格式化到 PSR-2
-
1.9 2019-08-03
- 一些修复。现在 UI 不显示“停留”在同一状态的事件。
- 现在它使用 eftec/minilang 2.6,允许使用 "else"。
- UI 更简化。
- 添加了 createColsTable() 方法。
-
1.8 2019-07-29 一些清理和 setPdoOne(),getPdoOne() 方法;
-
1.7 2019-06-16 许多更改。
-
1.6 2018-12-26 现在 MiniLang 是一个独立的依赖项。
-
1.5 2018-12-23 圣诞更新(顺便说一句,真是个糟糕的日子)。
- 现在语言解析方式不同。空格不再是必需的。
- "when timeout" 没有被弃用。现在它被称为 "when always"。
-
1.4 2018-12-12
- 一些修复。
-
1.3 2018-12-11
- 添加了 addEvent() 和 callEvent() 方法
- 将 timeout 和 fulltimeout 添加到转换语言中
- 现在转换不需要 timeout。
- 不再使用 idRef。
-
1.2 2018-12-09 更新依赖项
-
1.1 2018-12-09 一些修正。
-
1.0 2018-12-08 第一个(非测试版)版本。
缺少什么
事件和超时- 大多数单元测试,
现在它只是基本的。单元测试是真实的,但仍然很基础。 - 增加日志功能。