简体   繁体   中英

How to dynamically change the mode of a Dexterity behavior field to read-only?

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 BrowserView which has much more possibilities than the very limited content_status_modify Script (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.xml of you workflow (Example):

  <transition new_state="somestate" title="Some Title" transition_id="transition_id" after_script="" before_script="" trigger="USER">
    <action category="workflow" icon="" url="%(content_url)s/some-other-modify-status-script?transition=transition_di">Some Title</action>
    <guard>
      <guard-role>Contributor</guard-role>
      <guard-role>Manager</guard-role>
      <guard-role>Reviewer</guard-role>
      <guard-role>Site Administrator</guard-role>
    </guard>
  </transition>

This example changes the url from content_status_modify to some-other-modify-status-script

Here 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:

  • Invariant: Try to use simple invariants as far as possible. I assume you're using the catalog to get the necessary data. You can get the portal with hooks.getSite() and further also the catalog.This way all the logic is located directly in your behavior.
  • directives form validator decorator --> https://pypi.python.org/pypi/plone.directives.form#validators

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 handleApply method and raise a WidgetActionExecutionError or ActionExecutionError . 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.html

EDIT: 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM