[wf] new methods to build wf w/ workflow transition 3.5
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Tue, 25 Aug 2009 18:24:54 +0200
branch3.5
changeset 2986 d8f2e53702be
parent 2985 79185b3ccf2c
child 2987 5082dec70ed8
[wf] new methods to build wf w/ workflow transition
entities/wfobjs.py
--- a/entities/wfobjs.py	Tue Aug 25 13:36:02 2009 +0200
+++ b/entities/wfobjs.py	Tue Aug 25 18:24:54 2009 +0200
@@ -94,9 +94,7 @@
     # wf construction methods ##################################################
 
     def add_state(self, name, initial=False, **kwargs):
-        """method to ease workflow definition: add a state for one or more
-        entity type(s)
-        """
+        """add a state to this workflow"""
         state = self.req.create_entity('State', name=unicode(name), **kwargs)
         self.req.execute('SET S state_of WF WHERE S eid %(s)s, WF eid %(wf)s',
                          {'s': state.eid, 'wf': self.eid}, ('s', 'wf'))
@@ -107,12 +105,9 @@
                              {'s': state.eid, 'wf': self.eid}, ('s', 'wf'))
         return state
 
-    def add_transition(self, name, fromstates, tostate,
-                       requiredgroups=(), conditions=(), **kwargs):
-        """method to ease workflow definition: add a transition for one or more
-        entity type(s), from one or more state and to a single state
-        """
-        tr = self.req.create_entity('Transition', name=unicode(name), **kwargs)
+    def _add_transition(self, trtype, name, fromstates,
+                        requiredgroups=(), conditions=(), **kwargs):
+        tr = self.req.create_entity(trtype, name=unicode(name), **kwargs)
         self.req.execute('SET T transition_of WF '
                          'WHERE T eid %(t)s, WF eid %(wf)s',
                          {'t': tr.eid, 'wf': self.eid}, ('t', 'wf'))
@@ -122,12 +117,32 @@
             self.req.execute('SET S allowed_transition T '
                              'WHERE S eid %(s)s, T eid %(t)s',
                              {'s': state, 't': tr.eid}, ('s', 't'))
+        tr.set_transition_permissions(requiredgroups, conditions, reset=False)
+        return tr
+
+    def add_transition(self, name, fromstates, tostate,
+                       requiredgroups=(), conditions=(), **kwargs):
+        """add a transition to this workflow from some state(s) to another"""
+        tr = self._add_transition('Transition', name, fromstates,
+                                  requiredgroups, conditions, **kwargs)
         if hasattr(tostate, 'eid'):
             tostate = tostate.eid
         self.req.execute('SET T destination_state S '
                          'WHERE S eid %(s)s, T eid %(t)s',
                          {'t': tr.eid, 's': tostate}, ('s', 't'))
-        tr.set_transition_permissions(requiredgroups, conditions, reset=False)
+        return tr
+
+    def add_wftransition(self, name, subworkflow, fromstates, exitpoints,
+                       requiredgroups=(), conditions=(), **kwargs):
+        """add a workflow transition to this workflow"""
+        tr = self._add_transition('WorkflowTransition', name, fromstates,
+                                  requiredgroups, conditions, **kwargs)
+        if hasattr(subworkflow, 'eid'):
+            subworkflow = subworkflow.eid
+        self.req.execute('SET T subworkflow WF WHERE WF eid %(wf)s,T eid %(t)s',
+                         {'t': tr.eid, 'wf': subworkflow}, ('wf', 't'))
+        for fromstate, tostate in exitpoints:
+            tr.add_exit_point(fromstate, tostate)
         return tr
 
 
@@ -191,7 +206,6 @@
             self.req.execute('DELETE T condition R WHERE T eid %(x)s',
                              {'x': self.eid}, 'x')
         for gname in requiredgroups:
-            ### XXX ensure gname validity
             rset = self.req.execute('SET T require_group G '
                                     'WHERE T eid %(x)s, G name %(gn)s',
                                     {'x': self.eid, 'gn': gname}, 'x')
@@ -232,6 +246,50 @@
     def destination(self):
         return self.subwf.initial
 
+    def add_exit_point(self, fromstate, tostate):
+        if hasattr(fromstate, 'eid'):
+            fromstate = fromstate.eid
+        if hasattr(tostate, 'eid'):
+            tostate = tostate.eid
+        self.req.execute('INSERT SubWorkflowExitPoint X: T subworkflow_exit X, '
+                         'X subworkflow_state FS, X destination_state TS '
+                         'WHERE T eid %(t)s, FS eid %(fs)s, TS eid %(ts)s',
+                         {'t': self.eid, 'fs': fromstate, 'ts': tostate},
+                         ('t', 'fs', 'ts'))
+
+    def get_exit_point(self, state):
+        """if state is an exit point, return its associated destination state"""
+        if hasattr(state, 'eid'):
+            state = state.eid
+        stateeid = self.exit_points().get(state)
+        if stateeid is not None:
+            return self.req.entity_from_eid(stateeid)
+        return None
+
+    @cached
+    def exit_points(self):
+        result = {}
+        for ep in self.subworkflow_exit:
+            result[ep.subwf_state.eid] = ep.destination.eid
+        return result
+
+    def clear_all_caches(self):
+        super(WorkflowableMixIn, self).clear_all_caches()
+        clear_cache(self, 'exit_points')
+
+
+class SubWorkflowExitPoint(AnyEntity):
+    """customized class for SubWorkflowExitPoint entities"""
+    id = 'SubWorkflowExitPoint'
+
+    @property
+    def subwf_state(self):
+        return self.subworkflow_state[0]
+
+    @property
+    def destination(self):
+        return self.destination_state[0]
+
 
 class State(AnyEntity):
     """customized class for State entities"""