Reputation: 110476
I am working on a complex validation in a dexterity content type which should check the dependencies across several fields at the workflow transition time - I want it to work in the SimplePublicationWorkflow being triggered when the content is sent from "private" to "pending".
I've registered an event listener for IBeforeEvent and hooked it up - but nothing done there short of raising an exception can stop the transition from happening. (and if you raise an exception there, it goes uncaught and the user sees an error page instead of a custom message).
So, what is the recommended way to validate a transition in modern Plone? I've came across documentation suggesting adding External methods to be called on the Guard expression of the transition - but I would not like to use external methods, and if possible, I'd like to keep the default workflow. Creating a custom one is an option provided a clean way to do the check.
Upvotes: 4
Views: 334
Reputation: 2876
Just for the record; I found another use case for this today and I monkey patched Products.DCWorkflow as a proof-of-concept:
configure.zcml
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:monkey="http://namespaces.plone.org/monkey">
<monkey:patch
description="Allow aborting workflow transitions"
class="Products.DCWorkflow.DCWorkflow.DCWorkflowDefinition"
original="doActionFor"
replacement=".patches.doActionFor"
/>
<subscriber
for="Products.DCWorkflow.interfaces.IBeforeTransitionEvent"
handler=".subscribers.validate_workflow_transition"
/>
</configure>
subscribers.py
def validate_workflow_transition(event):
if not check_something():
raise MyException
patches.py
def doActionFor(self, ob, action, comment='', **kw):
...
# XXX: above this everything is included without any changes
# monkey patch replaces only the last line
try:
self._changeStateOf(ob, tdef, kw)
except MyException:
# do something
pass
The proof-of-concept worked as expected but I was not satisfied with the ending UI, so I decided to follow Martijn's advice and re-implement everything as a guard; it will need additional code to set the guard on all workflow transitions involved (and remove them on uninstall), and a browser view and viewlet to display a message explaining why the transition is not available, but it will be cleaner at the end.
Upvotes: 0
Reputation: 1123410
The recommended way is to set a guard instead.
The guard expression should be able to look up a view to facilitate more complex guard code, but when a guard returns False
the transition isn't even listed as available.
Upvotes: 3