Documentation Archive Developer
Search
PATH  WebObjects 4.5 Documentation > EOControl Reference

Table of Contents

EOValidation



Validating Individual Properties

The most general method for validating individual properties, validateValue:forKey:, validates a property indirectly by name (or key). This method is responsible for two things: coercing the value into an appropriate type for the object, and validating it according to the object's rules. The default implementation provided by NSObject consults the object's EOClassDescription (using the EOEnterpriseObject informal protocol method classDescription) to coerce the value and to check for basic errors, such as a null value when that isn't allowed. If no basic errors exist, this default implementation then validates the value according to the object itself. It searches for a method of the form validateKey: and invokes it if it exists. These are the methods that your custom classes can implement to validate individual properties, such as validateAge: to check that the value the user entered is within acceptable limits. The validateAge: method should return nil, indicating the value is acceptable, or an NSException created by calling the NSException method validationExceptionWithFormat:.

Coercion is performed automatically for you (by the EOClassDescription), so all you need handle is validation itself. Since you can implement custom validation logic in the validateKey: methods, you rarely need to override the EOValidation method validateValue:forKey:. Rather, the default implementation provided by NSObject is generally sufficient.

As an example of how validating a single property works, suppose that Member objects have an age attribute stored as an integer. This attribute has a lower limit of 16, defined by the Member class. Now, suppose a user types "12" into a text field for the age of a member. The value comes into the Framework as a string. When validateValue:forKey: is invoked to validate the new value, the method uses its EOClassDescription to convert the string "12" into an NSNumber, then invokes validateAge: with that NSNumber. The validateAge: method compares the age to its limit of 16 and returns an exception to indicate that the new value is not acceptable.

- (NSException *)validateAge:(NSNumber *)age
{
    if ([age intValue] < 16) {
        return [NSException
            validationExceptionWithFormat:@"Age of %@ is below minimum.", age];
    }
    return nil;
}

The method validationExceptionWithFormat: used in the above example is a method that the Framework adds to NSException for convenient creation of validation exceptions.


When Properties are Validated

The Framework validates all of an object's properties before the object is saved to an external source-either inserted or updated. Additionally, you can design your application so that changes to a property's value are validated immediately, as soon as a user attempts to leave an editable field in the user interface (in Java Client and Application Kit applications only). Whenever an EODisplayGroup sets a value in an object, it sends the object a validateValue:forKey: message, allowing the object to coerce the value's type, perform any additional validation, and return an exception if the value isn't valid. By default, the display group leaves validation errors to be handled when the object is saved, using validateValue:forKey: only for type coercion. However, you can use the EODisplayGroup method setValidatesChangesImmediately: with an argument of YES to tell the display group to immediately present an attention panel whenever a validation error is encountered.


Validating Before an Operation

The remaining EOValidation methods- validateForInsert, validateForUpdate, validateForSave, and validateForDelete-validate an entire object to see if it's valid for a particular operation. These methods are invoked automatically by the Framework when the associated operation is initiated. NSObject provides default implementations, so you only have to implement them yourself when special validation logic is required. For example, you can override these methods in your custom enterprise object classes to allow or refuse the operation based on property values. For example, a Fee object might refuse to be deleted if it hasn't been paid yet. Or you can override these methods to perform delayed validation of properties or to compare multiple properties against one another; for example, you might verify that a pair of dates is in the proper temporal order.

- (NSException *)validateForSave
{
    NSException *exception = [super validateForSave];
    NSException *myException = nil;

    if ([startDate compare:endDate] == NSOrderedDescending) {
        myException = [NSException 
            validationExceptionWithFormat:@"Start date must precede end date."];
    }
    if (exception && myException) {
        exception = [NSException aggregateExceptionWithExceptions:
            [NSArray arrayWithObjects:exception, myException, nil]];
    } else if (myException) {
        exception = myException;
    }
    return exception;
}

Note that this method also invokes super's implementation. This is important, as the default implementations of the validateFor... methods pass the check on to the object's EOClassDescription, which performs basic checking among properties, including invoking validateValue:forKey: for each property. The access layer's EOEntityClassDescription class verifies constraints based on an EOModel, such as delete rules. For example, the delete rule for a Department object might state that it can't be deleted if it still contains Employee objects.

The method validateForSave is the generic validation method for when an object is written to the external store. The default implementations of validateForInsert, validateForUpdate both invoke it. If an object performs validation that isn't specific to insertion or to updating, it should go in validateForSave.


Table of Contents