Open stojg opened 11 years ago
On second thoughts, I'm unclear how to connect the has_many back to WorkflowApplicable from WorkflowDefinition with a has_one, since WorkflowApplicable can be any type of DataObject.
WorkflowApplicable.php
public static $has_many = array(
'WorkflowDefinitions' => 'WorkflowDefinition',
);
WorkflowDefinition.php
public static $has_one = array(
'WorkflowApplicable' => 'DataObject'
);
Multiple workflows
Many months (years?) ago I started looking at ways of applying multiple workflows to objects, and came down to
The binding between WorkflowApplicable and WorkflowDefinition would make use of a new data object type that captured the item it's applied to (using same DataClass/DataID pattern used in WorkflowInstace), type (or arbitrary name) it is relevant for, and the workflow definition to use in that instance. Then WorkflowService::getDefinitionFor will need changing to figure out the relevant definition based on the type/state of the object.
Timed Transitions
WorkflowAction classes at present represent a "state" in the workflow, and I'm not sure I'd want to see it separated out into an explicit WorkflowState and WorkflowAction classes just yet without a compelling reason. My understanding of what you're getting at is that you're wanting to have more granular actions, ie
WorkflowState 1 .. * WorkflowAction
where the actions might be bound to 'events' for the state, ie
onEnterState -> WorkflowAction onExitState -> WorkflowAction on*State -> WorkflowAction
At the moment when I need this kind of thing I end up using an immediately executed action (ie it has one inbound transition and one outbound transition, meaning it'll get executed and immediately pass on to the next action). It's not exactly the cleanest representation, but unless you have very complex states, it suffices. But again, perhaps a compelling enough use case could be put forward for making the change.
For doing timed transitions in this structure, I'd first lean towards having a TimeDelayWorkflowAction that would be set to 'wait' for X number of hours/days or until a specific time, and then its execute() method would return true and its outbound transition followed. I guess I've always wanted to keep the complexity of the workflow transitions as simple as possible code wise and keep 'business' logic in the actions.
The binding between WorkflowApplicable and WorkflowDefinition would make use of a new data object type that captured the item it's applied to (using same DataClass/DataID pattern used in WorkflowInstace), type (or arbitrary name) it is relevant for, and the workflow definition to use in that instance. Then WorkflowService::getDefinitionFor will need changing to figure out the relevant definition based on the type/state of the object.
Seems fair, this would be 'default' SilverStripe pattern to solve this. I'll give it whirl if you're okey with it.
For doing timed transitions in this structure, I'd first lean towards having a TimeDelayWorkflowAction that would be set to 'wait' for X number of hours/days or until a specific time, and then its execute() method would return true and its outbound transition followed.
Yeah, that is basically what I would do as well.
I don't have a better compelling reason that it follows a state machine pattern that I recently implemented in javascript. In my point of view it separates the state to just be an arbitrary description of the current state that maps to the business workflow.
I believe that users and developers can easier conceptualize the flow by separating a state like publish from the actions that when something gets published a bunch of things should happen at the same time.
where the actions might be bound to 'events' for the state, ie
onEnterState -> WorkflowAction onExitState -> WorkflowAction on*State -> WorkflowAction
Yeah, this and being able to set actions on Transitions makes it very generalized, but maybe to generalized?
Here's my js impementation of a state maching: http://play.stojg.se/js/state.js
I've started work on the multiple workflows per objects, outstanding are more tests and more testing. https://github.com/stojg/advancedworkflow/commits/multiple-workflows
I'm currently looking at expanding the advancedworkflow to support timed transition. For example notifying content reviewers that they should have a look at something. I'm dumping a couple of ideas on how to support this. I'm keen on getting @nyeholt and @sminnee ideas on this.
Allow multiple workflows for a WorkflowApplicable extended objects
This allows us to configure multiple workflows per objects. Another approach would to use some sort of hierarchial state machine pattern or a state machine with decision trees, but I think that would complicate this a lot more.
An example would be to have:
This refactoring includes changing the
WorkflowApplicable
fromto
.. and change all the relevant UI elements to support that.
Create Transitions that are triggered via timers
Waiting for review - initial state
Notificated
Overdue
This will require transitions to be able to save triggerstamps persistance so it can be queried and exectuted. Most likely with the help of the
queuedjobs
module.How about creating a
WorkflowTimeTransition
?Other refactoring ideas
Break out Create state from WorkFlowAction
The current state should should reflect which state the current Workflow is in.
A State can have:
It changes the perception from actions to state:
Example:
Waiting for approval - Initial state
-> transition to State.Approved -> transition to State.Rejected
Approved
Rejected
Published
Abort
This makes states a bit more lightweight and are basically just placeholders for actions.
Allow Transitions to have actions
Good for sending notifications or scheduling embargos / offline tasks
This separates states from actions and makes actions more generic and it's easier to visualize the workflow.