-
Notifications
You must be signed in to change notification settings - Fork 0
/
StateTransition.cfc
97 lines (82 loc) · 3.08 KB
/
StateTransition.cfc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
<cfcomponent displayname="StateTransition" output="false">
<cfset instance = structNew() />
<cffunction name="init" access="public" output="false">
<cfargument name="from" type="string" required="true" />
<cfargument name="to" type="string" required="true" />
<cfargument name="guard" type="string" required="false" default="" />
<cfscript>
instance.from = arguments.from;
instance.to = arguments.to;
instance.guard = arguments.guard;
</cfscript>
<cfreturn this />
</cffunction>
<cffunction name="getMemento" access="public" output="false">
<cfscript>
var st = structNew();
st.ToState = instance.to;
st.FromState = instance.from;
st.guard = instance.guard;
return st;
</cfscript>
</cffunction>
<cffunction name="guard" returntype="boolean" access="public" output="false">
<cfargument name="obj" required="true" />
<cfset var result = true />
<cfset var decorated = obj.getOriginalObject() />
<cfif len(instance.guard) and structKeyExists(decorated, instance.guard)>
<cfinvoke component="#decorated#" method="#instance.guard#" returnvariable="result" />
</cfif>
<cfreturn result />
</cffunction>
<cffunction name="perform" access="public" output="false">
<cfargument name="obj" required="true" />
<cfargument name="persistenceObject" required="false" />
<cfargument name="persistenceMethod" required="false" default="save" />
<cfscript>
var local = structNew();
if(not guard(obj)) {
return false;
}
local.isLoopback = obj.getCurrentState() eq getToState();
local.states = arguments.obj.getStates();
local.nextState = local.states[getToState()];
local.oldState = local.states[obj.getCurrentState()];
if(not local.isLoopback) {
if(local.nextState.before(obj)) {
// Set the state
obj.setInternalState(getToState());
// Do the update if we have an updater reference
if(structKeyExists(arguments, 'persistenceObject') and isObject(arguments.persistenceObject)) {
if(not persist(arguments.persistenceObject, arguments.persistenceMethod, obj)) {
local.nextState.fail(obj);
return false;
}
}
local.nextState.after(obj);
local.oldState.exit(obj);
} else {
return false;
}
}
return true;
</cfscript>
</cffunction>
<cffunction name="getFromState" access="public" returntype="string" output="false">
<cfreturn instance.from />
</cffunction>
<cffunction name="getToState" access="public" returntype="string" output="false">
<cfreturn instance.to />
</cffunction>
<cffunction name="persist" access="private" returntype="boolean" output="false">
<cfargument name="component" required="true" />
<cfargument name="method" required="true" />
<cfargument name="obj" required="true" />
<cfinvoke component="#arguments.component#" method="#arguments.method#" returnvariable="success">
<cfinvokeargument name="1" value="#arguments.obj#" />
</cfinvoke>
<!--- If the method returns void, assume it succeeded --->
<cfparam name="success" default="true" type="boolean" />
<cfreturn success />
</cffunction>
</cfcomponent>