validationplonez3c.formzope.interface

Plone - How can I make a validator validate a field from a behavior for a specific content type?


I am using Plone 4.3 and I have a form.SchemaForm plone.directives have an interface that has a start field from IEventBasic and a validator:

from datetime import timedelta
from plone.directives import form
from plone.app.contenttypes.interfaces import IEvent
from z3c.form import validator
from zope.component import provideAdapter
from zope.interface import Invalid

class IMyObject(form.SchemaForm)
    my_field_a = schema.TextLine(title='a_field')
    ...

class MyObject(Item):
    implements(IMyObject, IEvent)

class EndMyObjectValidator(validator.SimpleFieldValidator):
    def validate(self,value):
        #code for checking if end field is within a certain range from start field
        if self.end > self.start + timedelta(days=6):
            raise Invalid('The end date is not within range of the start date's week')

validator.WidgetValueDiscriminators(EndMyObjectValidator, field=IEventBasic['end'])
provideAdapter(EndMyObjectValidator)

In my type file (my.object.myobject.xml under profiles/default/types), I place the behavior in the behaviors section.

<behaviors>
    <element value="plone.app.event.dx.behaviors.IEventBasic"/>
</behaviors>

The problem is it validates the end field in any Event object or any object that implements the IEventBasic interface/schema.

I thought maybe since the Plone documentation says that the parameters 'view' and 'context' of WidgetValueDiscriminators accept an interface, then I could do either:

validator.WidgetValidatorDiscriminators(EndMyObjectValidator, view=IMyObject, field=IEventBasic['end'])

or

validator.WidgetValidatorDiscriminators(EndMyObjectValidator, context=IMyObject,field=IEventBasic['end']

Unfortunately, none of those trigger at all. I guess I'm misunderstanding what the context and view parameters actually do. How can I make it so the validators are specifically for dealing with MyObject?

Source: http://docs.plone.org/develop/addons/schema-driven-forms/customising-form-behaviour/validation.html

For now I am doing:

...
from gpcl.container.my_container import MyContainer

...

class EndMyObjectValidator(validator.SimpleFieldValidator):

    def validate(self,value):
        if self.widgets.form.portal_type <> 'my.object.myobject':
            return

        ...

validator.WidgetValueDiscriminators(EndMyObjectValidator, field=IEventBasic['end'])
provideAdapter(EndMyObjectValidator)

Update 2: I removed my comment before because it was for an unrelated problem. I changed the way I was checking for the type.


Solution

  • Ok, register your own Add Form and Subclassing the Default Dexterity Add Form. More Information about Validating in action handlers and Custom Add Forms

    in my task.py (Contenttype and so on...):

    # -*- coding: utf-8 -*-
    from zope.interface import implementer
    from zope.interface import Invalid
    from z3c.form import button
    from z3c.form import validator
    from z3c.form import util
    from z3c.form.interfaces import ActionExecutionError
    from z3c.form.interfaces import WidgetActionExecutionError
    from plone.dexterity.content import Item
    from plone.dexterity.browser import add
    from viisionar.training.interfaces import ITask
    from Products.statusmessages.interfaces import IStatusMessage
    from my.addon import _
    
    @implementer(ITask)
    class Task(Item):
        pass
    
    class AddForm(add.DefaultAddForm):
    
        portal_type = 'Task'
    
        def __init__(self, context, request, ti=None):
            super(AddForm, self).__init__(context, request, ti=None)
    
        @button.buttonAndHandler(_('Save'), name='save')
        def handleAdd(self, action):
    
            print "Handle Add"
            data, errors = self.extractData()
    
            if errors:
                self.status = self.formErrorsMessage
                return
    
            # Your Custom validation
    
            # Debug Do what yo want
    
            print data
    
            if error:
                """
                # Global Portal Message
                raise ActionExecutionError(Invalid(_(u"Please provide a valid end date")))
    
                # or
    
                # Error Message in Widget
                raise WidgetActionExecutionError('IEventBasic.end', Invalid(u"Please put the the right end date"))
                """
            # /Your Custom validation
    
            obj = self.createAndAdd(data)
    
            if obj is not None:
                # mark only as finished if we get the new object
                self._finishedAdd = True
                IStatusMessage(self.request).addStatusMessage(
                    self.success_message, "info"
                )
    
    class AddView(add.DefaultAddView):
        form = AddForm
    

    in my configure.zcml i register the custom Add form

    <adapter
        for="
            Products.CMFCore.interfaces.IFolderish
            zope.publisher.interfaces.browser.IDefaultBrowserLayer
            plone.dexterity.interfaces.IDexterityFTI"
        provides="zope.publisher.interfaces.browser.IBrowserPage"
        factory="my.addon.task.AddView"
        name="Task" />
    
    <class class="my.addon.task.AddView">
        <require
            permission="cmf.AddPortalContent"
            interface="zope.publisher.interfaces.browser.IBrowserPage"/>
    </class>
    

    in my task.xml Definition:

    <property name="factory">Task</property>
    <property name="schema">my.addon.interfaces.ITask</property>
    <property name="klass">my.addon.task.Task</property>
    <property name="behaviors">
      <element value="plone.app.content.interfaces.INameFromTitle" />
      <element value="plone.app.event.dx.behaviors.IEventBasic"/>
    </property>