#217: Use Adaptation for Workflow Assignment
- Contents
- Proposed by
- Alec Mitchell
- Proposal type
- Architecture
- Assigned to release
- State
- completed
Motivation
Currently it is very difficult to use alternate mechanisms for assigning workflow. For example CMFPlacefulWorkflow needs to monkey patch the workflow tool in order to support assignment based on location. There is also no way to change the workflow assigned to an object based on "sub-type", i.e. a marker interface applied to content. Further, though the workflow engine is built to work with non-CMF content, the workflow assignment mechanism assumes the existence of a portal_type. This inflexibility can easily be addressed by using adaptation to determine which workflows apply to a particular object.
Proposal
Providing workflow assignment via adaptation is a pretty trivial task which can be made fully backward compatible. We simply need to replace the content of the WorkflowTool.getWorkflowsFor method with a lookup via adaptation. For simplicity we could use a single adaptation:
def getWorkflowsFor(self, ob)
return IWorkflowChain(ob)
Where IWorkflowChain is a simple iterable of workflow objects. However, in order to support more complex usecases, which might need to change workflow policy portal wide, it makes sense to use a multi-adapter on the object and the workflow tool:
def getWorkflowsFor(self, ob):
return getMultiAdapter((ob, self), IWorkflowChain)
This would allow for something like CMFPlacefulWorkflow to, on install, mark the workflow tool with an interface indicating a policy change, and then provide a specialized adapter for the marked tool. The default adapter itself would be simple:
class DefaultWorkflowLookup(object):
implements(IWorkflowChain)
adapts(IDynamicType, IWorkflowTool)
def __init__(self, obj, tool):
self.tool = tool
self.obj = obj
def __iter__(self):
tool = self.tool
for wf_id in tool.getChainFor(self.obj):
wf = tool.getWorkflowById(wf_id)
if wf is not None:
yield wf
Alternatively, we could replace getChainFor instead of getWorkflowsFor, so that the task of looking up the workflow by id would be left up to the tool and wouldn't have to be implemented by every adapter. However, this would eliminate the potential to use workflows defined outside the tool (perhaps even non-persistent workflows).
Ideally this would be done in CMFCore. However, it's certainly feasible to do it inside of the CMFPlone workflow tool if no major release of CMF is imminent. The changes could easily be merged back into the core as needed.
Another, non-mandatory step would be to re-implement the CMFPlacefulWorkflow monkeypatch as an adapter using this pattern and have its Product install method apply an appropriate marker interface to the workflow tool (the uninstall would of course remove the marker).
Deliverables
- The interface for IWorkflowChain would need to be created.
- The getWorkflowsFor method would need to be rewritten/overridden, and a test would need to be written to demonstrate the adaptation based mechanism.
- The default adapter would need to be created, and existing tests would need to be changed to test that adapter specifically.
- Some documentation on how to provide a custom workflow assignment mechanism should be provided.
Risks
There should be no risks for this change. The only risk is that our workflow tool will deviate further from the CMF version, hopefully we can get this code applied in CMFCore sooner rather than later.
Previously Existing Work
Kapil has proposed a similar solution on the CMF mailing list, but no-one paid attention:
http://article.gmane.org/gmane.comp.web.zope.cmf/12834/match=using+adapters+workflow+tool
His code is available on the CMFBlackBird product, at Object Realms SVN:
http://svn.objectrealms.net/view/public/browser/cmfblackbird/trunk/workflow.py
Hope that's useful to you...
updated code reference
http://svn.objectrealms.net/view/public/browser/ore.adaptedworkflow/trunk/src/ore/adaptedworkflow
+1 on the idea
Framework team vote
Framework team vote
Does this also mean that you theoretically could have a setting on an object which workflows it uses? That would be nice (with the proper UI of course ;-))
A CMFPlacefulWorkflow extension
#2 This approach object by object is complementary to the CMFPlacefulWorkflow that make possible a CMF like workflow strategy (id est by type) for a part of the site. The next step should be to have a more open implementation of strategies to be able to run by language workflow for example.