collective.googlenews is a package that implements, among other things, a behavior do add 2 new fields to a Dexterity-based content type.
One of this fields (called standout_journalism) have some special requirements that have proved complicated to implement:
- any site can only have 7 items marked as standout in the last week
- to be counted, and item must be declared as standout (a boolean field) and must be published
I have to implement 2 different validations then:
- on the workflow transition, avoid publication of items marked as standout when we already have 7
- on the edit form, avoid marking a published item as standout when we already have 7
I was able to solve first part using workflow guards and a viewlet that shows a warning explaining why the transition is disabled, but I'm not sure about the second one.
I have created an invariant and the form returns an error if the user try to change the value of the field on a published item.
The problem is we think that behavior should be different: we want to avoid changing the value of that field (marking it as read-only) when marking an item as standout should not be allowed.
Should I create my own widget? Should I override the update method in the field? Should I override the updateWidgets method in the form?
On any case I have no idea how to proceed because the documentation is not clear about fields added as with behaviors.
Any pointers to code examples are much appreciated.
Workflow guards:
Just FYI instead of workflow guards, we used to point to a other workflow transition script. In our case a
BrowserViewwhich has much more possibilities than the very limitedcontent_status_modifyScript (at least in Plone 4).It's further also easier to test and I had some issues with workflow guards... but I can't remember :-( (Probably I missed some payload/context/request).
You can set the Workflow transition script with the
definition.xmlof you workflow (Example):This example changes the url from
content_status_modifytosome-other-modify-status-scriptHere is a full example of an custom status modify script
The important part happens here on line 21. It checks for some constrains and if it's valid the transition will happen, if not, the transition is not even initialised.
I'm sure in your case you can short it to just a few, readable lines.
The full example has a "Constraint System" (Adapter) behind, which allows to register constraints, that's why there are several more lines of code...
Validating the form:
hooks.getSite()and further also the catalog.This way all the logic is located directly in your behavior.If this is, for some reason, not possible: You need to do the validation on form level. This means customising the dexterity edit form.
In there I would hack into the
handleApplymethod and raise aWidgetActionExecutionErrororActionExecutionError. Depends if you want a Error message on the widget or a general error message on the form. Check http://garbas.github.io/plone-z3c.form-tutorial/validation.htmlEDIT: In addition to the form validation (very hight level) you can make sure, also low level modifications are validated In this case you may write your own field setter in your behavior.
Working example of custom getter/setter for a DX type. FYI: I recently also found this issue in the plone.app.dx repo
This should be easily adapted into a behavior, since by default you can choose between a PropertyStorage and AnnotationStorage for the behavior data.