No more schema binding
No more schema field binding
Status: IsProposal
Author
Problem
There is a "feature" of schema fields that I really don't want to keep. This feature is called "binding". A field can be "bound" to an object. This creates a new field instance, which is a clone of the original, that has a `context` attribute which is some object. The object may, for example, be an object that has an attribute that is specified by the field.
Why do we need this?
- Field validation may need to look up (acquire) components. For example, a permission field should allow only defined permission ids. The defined permission ids are obtained by getting all of the names of IPermission? utilities from the utility service.
- We may need to consider object identity, or a current object value.
To illustrate this, consider a bumper car ride. We have a system that lets us assign bumper cars to riders. Clearly we should only assign unoccupied bumper cars. But suppose that someone is already in a bumper car. In that case, the car they are sitting in should be a valid choice for them, even though it is occupied. To properly validate, or to generate a correct UI, we need to take into account the identity of the rider we're picking a bumper car for.
- Perhaps there are other cases where we want to take context into account for some reason. Perhaps allowable values for a field depend on data acquired from a folder. This is hypothetical, but people I trust have told me that this is likely.
Here's a non-reason for needing this: relationships between fields. Suppose we have two fields, `max` and `min`. We want to assure that the `max` field value is not less than the `min` field value. If we expressed this as a field constraint, we'd need to have an object that actually had the values. It turns out that this is a bad idea. Field constraints should only constrain values for that field, without regard to other fields. Rather, we express constraints involving multiple fields using interface invariants. Why? Because otherwise, the validation of fields depends on the order they are processed. Consider the `max` and `min` case. Do we put the constraint on `max`, or `min`, or `both`? If you put the constraint on both, then you will be unable to make certain changes. Suppose we have existing values 3 and 4. The user changes them to 5 and 6. If we check the constraint on `min` first, then the constraint will fail because the new `min` is greater than the old `max`. If we check the constraint on `max` first, then we can't change the values to 1 and 2. The saner approach is to either check invariants after the values have been assigned, or to apply the invariants to the full collection of input data.
Reason 1, above, is addressed by:
http://dev.zope.org/Zope3/FixedDefaultComponentLookup
But we're still stuck with reasons 2 and 3.
Proposal
A. Validation
Fields will provide a validation method that can be called to validate a value. This method must do its work without any context, because it won't have any.
In Zope (or in applications that need context-sensitive fields) we'll validate by:
- Calling the field validate method
- Getting multi-subscription adapters and asking them to validate the value:
The logic would go something like this:
>>> field.validate(value)
>>> for validator in zapi.subscribers((field, context), IValidator):
... validator.validate(value)
B. Widgets
Widgets will become multi-views:
>>> widget = getMultiView((field, context), request, IInputWidget)
So, in the bumper car example, when editing a rider, we'd use:
>>> widget = getMultiView((field, rider), request, IInputWidget)
But, when adding a rider, we'd use an adding object as the context:
>>> widget = getMultiView((field, adding), request, IInputWidget)
More on example 2 --poster, 2004/04/08 11:36 EST reply
The only reservation I have to this solution is that I feel the sort of validation exemplified above by the bumper car story is going to be so prevalent that the canonical solution should be something available outside of zope.app, or more accurately, something not dependent on both the interface package and the CA package.
Here's another, simpler example than the bumper car one of the same type:
A child wishes to make a list of his friends. The choices should include every child at school except himself.
We use that pattern at least a couple of times in our software. Not allowing for it generally is a bit of a handicap to the schema package, IMO. Not too bad I guess--someone can always implement the functionality another way--but ideally there would be a canonical, approved approach in the top-level interface/schema stuff.
That said, this solution works for all of my immediate needs, so I can't complain too much. :-)
What about context for vocabularies/sources? --poster, 2005/08/04 22:11 EST reply
Vocabularies and sources sometimes need context to determine their available values. This is a field issue, it seems to me, not a widget issue, or an external validation issue. If the bumper car example is implemented with a vocabulary or source, for instance, it should itself know the context, so that available bumper cars do not include the current bumper car, and the current bumper car is not valid. These could both be implemented with a widget and validator, respectively, but that breaks the contract of a vocabulary or source (they are supposed to provide those capabilities).
