Skip to content

Commit

Permalink
Add DataExctractedEvent, which is thrown after data and errors are ex…
Browse files Browse the repository at this point in the history
…tracted from widgets.
  • Loading branch information
thet committed Mar 31, 2014
1 parent 757300d commit 77ccddb
Show file tree
Hide file tree
Showing 8 changed files with 93 additions and 11 deletions.
3 changes: 2 additions & 1 deletion CHANGES.txt
Expand Up @@ -5,7 +5,8 @@ CHANGES
3.2.1 (unreleased)
------------------

- Nothing changed yet.
- Add DataExctractedEvent, which is thrown after data and errors are extracted
from widgets.


3.2.0 (2014-03-18)
Expand Down
10 changes: 10 additions & 0 deletions src/z3c/form/events.py
@@ -0,0 +1,10 @@
from z3c.form.interfaces import IDataExtractedEvent
from zope.interface import implementer


@implementer(IDataExtractedEvent)
class DataExctractedEvent(object):
def __init__(self, data, errors, form):
self.data = data
self.errors = errors
self.form = form
7 changes: 5 additions & 2 deletions src/z3c/form/form.py
Expand Up @@ -27,6 +27,7 @@
from zope.schema.fieldproperty import FieldProperty

from z3c.form import button, field, interfaces, util
from z3c.form.events import DataExctractedEvent
from z3c.form.i18n import MessageFactory as _


Expand Down Expand Up @@ -98,7 +99,7 @@ def handleActionError(event):


@zope.interface.implementer(interfaces.IForm,
interfaces.IFieldsForm)
interfaces.IFieldsForm)
class BaseForm(browser.BrowserPage):
"""A base form."""

Expand Down Expand Up @@ -143,7 +144,9 @@ def extractData(self, setErrors=True):
'''See interfaces.IForm'''
self.widgets.setErrors = setErrors
self.widgets.ignoreRequiredOnExtract = self.ignoreRequiredOnExtract
return self.widgets.extract()
data, errors = self.widgets.extract()
zope.event.notify(DataExctractedEvent(data, errors, self))
return data, errors

def update(self):
'''See interfaces.IForm'''
Expand Down
40 changes: 40 additions & 0 deletions src/z3c/form/form.txt
Expand Up @@ -407,6 +407,18 @@ Let's go back to a normal status to continue the test.

>>> request.response.setStatus(200)


Registering a custom event handler for the DataExctractedEvent
--------------------------------------------------------------

>>> data_extracted_eventlog = []
>>> from z3c.form.events import DataExctractedEvent
>>> @zope.component.adapter(DataExctractedEvent)
... def data_extracted_logger(event):
... data_extracted_eventlog.append(event)
>>> zope.component.provideHandler(data_extracted_logger)


Submitting an add form successfully
-----------------------------------

Expand Down Expand Up @@ -442,6 +454,20 @@ the form with the "Add" button, the person should be added to the root folder:
20


Check, if DataExctractedEvent was thrown
-----------------------------------------

>>> event = data_extracted_eventlog[0]
>>> 'name' in event.data
True

>>> event.errors
()

>>> event.form
<PersonAddForm object at ...


Submitting an add form with invalid data
----------------------------------------

Expand All @@ -468,6 +494,20 @@ message:
>>> addForm.widgets['name'].error
<ErrorViewSnippet for RequiredMissing>


Check, if event was thrown:

>>> event = data_extracted_eventlog[-1]
>>> 'id' in event.data
True

>>> event.errors
(<ErrorViewSnippet for RequiredMissing>,)

>>> event.form
<PersonAddForm object at ...


Let's now render the form:

>>> addTemplate(addForm)
Expand Down
14 changes: 9 additions & 5 deletions src/z3c/form/group.py
@@ -1,4 +1,4 @@
##############################################################################
#########################################################################
#
# Copyright (c) 2007 Zope Foundation and Contributors.
# All Rights Reserved.
Expand All @@ -16,10 +16,13 @@
$Id$
"""
__docformat__ = "reStructuredText"
import zope.component

from z3c.form import form, interfaces
from zope.interface import implementer
from z3c.form.events import DataExctractedEvent

import zope.component
import zope.event


@implementer(interfaces.IGroup)
Expand Down Expand Up @@ -70,11 +73,11 @@ def extractData(self, setErrors=True):
errors += groupErrors
else:
errors = groupErrors
zope.event.notify(DataExctractedEvent(data, errors, self))
return data, errors

def applyChanges(self, data):
'''See interfaces.IEditForm'''
descriptions = []
content = self.getContent()
changed = form.applyChanges(self, content, data)
for group in self.groups:
Expand All @@ -101,6 +104,7 @@ def extractData(self, setErrors=True):
errors += groupErrors
else:
errors = groupErrors
zope.event.notify(DataExctractedEvent(data, errors, self))
return data, errors

def applyChanges(self, data):
Expand All @@ -118,8 +122,8 @@ def applyChanges(self, data):
zope.lifecycleevent.Attributes(interface, *names))
# Send out a detailed object-modified event
zope.event.notify(
zope.lifecycleevent.ObjectModifiedEvent(content,
*descriptions))
zope.lifecycleevent.ObjectModifiedEvent(
content, *descriptions))

return changed

Expand Down
24 changes: 22 additions & 2 deletions src/z3c/form/group.txt
Expand Up @@ -174,6 +174,18 @@ We can now render the form:
</body>
</html>


Registering a custom event handler for the DataExctractedEvent
--------------------------------------------------------------

>>> data_extracted_eventlog = []
>>> from z3c.form.events import DataExctractedEvent
>>> @zope.component.adapter(DataExctractedEvent)
... def data_extracted_logger(event):
... data_extracted_eventlog.append(event)
>>> zope.component.provideHandler(data_extracted_logger)


Let's now submit the form, but forgetting to enter the address:

>>> request = testing.TestRequest(form={
Expand All @@ -199,8 +211,16 @@ Let's now submit the form, but forgetting to enter the address:
</ul>

As you can see, the template is clever enough to just report the errors at the
top of the form, but still report the actual problem within the group. So what
happens, if errors happen inside and outside a group?
top of the form, but still report the actual problem within the group.


Check, if DataExctractedEvent was thrown:

>>> len(data_extracted_eventlog) > 0
True


So what happens, if errors happen inside and outside a group?

>>> request = testing.TestRequest(form={
... 'form.widgets.firstName': u'Stephan',
Expand Down
5 changes: 5 additions & 0 deletions src/z3c/form/interfaces.py
Expand Up @@ -1116,6 +1116,11 @@ class IWidgetEvent(zope.interface.Interface):
description=_('The widget for which the event was created.'),
schema=IWidget)


class IAfterWidgetUpdateEvent(IWidgetEvent):
"""An event sent out after the widget was updated."""


class IDataExtractedEvent(zope.interface.Interface):
"""Event thrown after data and errors are extracted from widgets.
"""
1 change: 0 additions & 1 deletion src/z3c/form/tests/test_doc.py
Expand Up @@ -17,7 +17,6 @@
import itertools
import re
import unittest

from zope.testing import renormalizing

from z3c.form import testing
Expand Down

0 comments on commit 77ccddb

Please sign in to comment.