[Zope-dev] Form error handling for Rack-stored PD classes in O-O application
Itai Tavor
itai@optusnet.com.au
Wed, 4 Apr 2001 11:39:24 +1000
Hi,
I often have more luck the second time I ask a question... let's see
if this rule holds.
I'm struggling with checking and reporting errors in forms that
create or modify properties of PD classes in a ZPatterns application.
Automatic checks using Zope's built-in constraints or something like
ValueHandler won't cut it, because they can't cover all the required
rules - for example, checking if a Product SKU is being set to an
existing SKU, or that a Customer is trying to use an email address
already in use (and also because I want to return the form page with
the errors indicated, rather than a generic error page). So I need a
specific verification method for each class. This method will be used
both when an object is edited and when its created. To use the method
when creating an object, I either have to place it in the Specialist
- which is bad, because the PD class should provide its validation
code, or call it at commit time, using a SkinScript WHEN OBJECT
CREATED,CHANGED clause. But verification methods called at commit
time do their checks on the object properties, not on any submitted
form field values. So they can test that a password is reasonably
secure, but can't check that passwords typed in two form fields are
identical.
One thing I can do is define a editInstance method which would verify
the values in REQUEST.form and then call manage_changeProperties, or
store a list of errors in the REQUEST and raise a 'FormError'
exception. But I can't let this exception propagate freely, I have to
catch it so I can display an appropriate error page. Also, if a form
results in the creation of more than one object, I want to display
all the errors that result from the creation of all the objects, but
if the first object raises an exception, I can't create the second
one (especially if the second one expects to get the id of the first).
Or I could forget about exceptions and simply return an error list
from editInstance. Then it would be up to the method calling
editInstance to raise an exception to roll back the created objects.
This is the only workable solution I got at the moment... I can get
it to work, but I've chased solutions in the past that seemed good
but ended up crashing... so I'd really appreciate any comments on
possible flaws or problems I'm not seeing, or any other, better
solutions.
This is what it would look like (just an example, not showing cases
where more complex stuff happens, like 2 objects being created with a
single form):
In Customer (DataSkin PD class):
def editInstance(self, REQUEST, errors):
err = self.verify(REQUEST)
if err != {}:
errors.update(err)
else:
self.manage_changeProperties(REQUEST)
def editInstance_html(self, REQUEST, RESPONSE):
"""Action method for editInstanceForm_html"""
errors = {}
self.editInstance(REQUEST, errors)
if errors != {}:
html = self.editInstanceForm_html(self, REQUEST, errors=errors)
raise 'FormError', html
RESPONSE.redirect('editInstanceForm_html?message=Changes%20saved.')
def verify(self, REQUEST):
errors = {}
if REQUEST['name'] == '':
errors['name'] = 'Please provide a name'
return errors
In CustomerManager (Specialist):
addCustomer(self, REQUEST, errors):
ni = self.defaultRack.newItem()
ni.editInstance(REQUEST, errors)
return ni
addCustomer_html(self, REQUEST, RESPONSE):
"""Action method for addCustomerForm_html"""
errors = {}
ni = self.addCustomer(REQUEST, errors)
if errors != {}:
html = self.addCustomerForm_html(self, REQUEST, errors=errors)
raise 'FormError', html
RESPONSE.redirect('manageInstances_html?message=New%20customer%20created.')
And, of course, I can also have WHEN OBJECT ADDED,CHANGED CALL
self.ensure_valid(), to catch anything that might get by the above
checks. ensure_valid will raise its own error page, independent of
the above.
TIA for any help/comments
Itai
--
--
Itai Tavor -- "Je sautille, donc je suis." --
itai@optusnet.com.au -- - Kermit the Frog --
-- 'Supposing a tree fell down, Pooh, when we were underneath it?' --
-- 'Supposing it didn't,' said Pooh after careful thought. --