Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Retrieving validation limits from model and overriding validateValue #2

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CoreDataValidationTest.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
72BEF6CA185BAA77000FA0CB /* CoreData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72BEF6A5185BAA76000FA0CB /* CoreData.framework */; };
72BEF6D2185BAA77000FA0CB /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 72BEF6D0185BAA77000FA0CB /* InfoPlist.strings */; };
72BEF6D4185BAA77000FA0CB /* CoreDataValidationTestTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 72BEF6D3185BAA77000FA0CB /* CoreDataValidationTestTests.m */; };
EDF5ED4F18D37D4900CBA7DA /* fwLocalizedStrings.strings in Resources */ = {isa = PBXBuildFile; fileRef = EDF5ED4E18D37D4900CBA7DA /* fwLocalizedStrings.strings */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -62,6 +63,7 @@
72BEF6CF185BAA77000FA0CB /* CoreDataValidationTestTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "CoreDataValidationTestTests-Info.plist"; sourceTree = "<group>"; };
72BEF6D1185BAA77000FA0CB /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
72BEF6D3185BAA77000FA0CB /* CoreDataValidationTestTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CoreDataValidationTestTests.m; sourceTree = "<group>"; };
EDF5ED4E18D37D4900CBA7DA /* fwLocalizedStrings.strings */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; path = fwLocalizedStrings.strings; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -142,6 +144,7 @@
72BEF6A8185BAA76000FA0CB /* Supporting Files */ = {
isa = PBXGroup;
children = (
EDF5ED4E18D37D4900CBA7DA /* fwLocalizedStrings.strings */,
72BEF6A9185BAA76000FA0CB /* CoreDataValidationTest-Info.plist */,
72BEF6AA185BAA76000FA0CB /* InfoPlist.strings */,
72BEF6AD185BAA76000FA0CB /* main.m */,
Expand Down Expand Up @@ -245,6 +248,7 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
EDF5ED4F18D37D4900CBA7DA /* fwLocalizedStrings.strings in Resources */,
72BEF6C0185BAA77000FA0CB /* Images.xcassets in Resources */,
72BEF6AC185BAA76000FA0CB /* InfoPlist.strings in Resources */,
722C2BFD188A6146001A0565 /* SSViewController.xib in Resources */,
Expand Down
151 changes: 131 additions & 20 deletions CoreDataValidationTest/Person.m
Original file line number Diff line number Diff line change
Expand Up @@ -14,31 +14,105 @@ @implementation Person
@dynamic firstName;
@dynamic lastName;

-(NSDictionary *)privateValidationPredicates { // used in case the model does not define limits
return @{@"firstName" : @[[NSPredicate predicateWithFormat:@"length >= 2"],[NSPredicate predicateWithFormat:@"length <= 10"]],
@"lastName" : @[[NSPredicate predicateWithFormat:@"length >= 2"],[NSPredicate predicateWithFormat:@"length <= 10"]],
@"someNumber" : @[[NSPredicate predicateWithFormat:@"self >= 2"],[NSPredicate predicateWithFormat:@"self <= 10"]]};
}

- (BOOL)validateFirstName:(id *)ioValue error:(NSError **)outError {

// firstName's validation is not specified in the model editor, it's specified here.
// field width: min 2, max 10

BOOL isValid = YES;
NSString *firstName = *ioValue;
-(BOOL)validateValue:(__autoreleasing id *)value forKey:(NSString *)key error:(NSError *__autoreleasing *)outError {
NSString *errorMessage;
NSInteger code;

if (firstName.length < 2) {

errorMessage = @"First Name must be at least 2 characters.";
code = NSValidationStringTooShortError;
BOOL isValid;
NSAttributeDescription *mad = [[[self entity] propertiesByName] valueForKey:key]; // refractor and don't shorten My Attribute Description ;)
if (NO == [mad isOptional] && nil == *value) {
// raise error because values must not be nil
errorMessage = NSLocalizedStringFromTableInBundle(@"fw_val_expectedNoNil", @"fwLocalizedStrings" , [NSBundle mainBundle], @"did not expected a nil value" );
code = 100;
isValid = NO;

} else if (firstName.length > 10) {

errorMessage = @"First Name can't be more than 10 characters.";
code = NSValidationStringTooLongError;
isValid = NO;

} else {
switch ([mad attributeType]) {
case NSInteger16AttributeType:
case NSInteger32AttributeType:
case NSInteger64AttributeType:
case NSDoubleAttributeType:
case NSFloatAttributeType:
case NSBooleanAttributeType:
isValid = [*value isKindOfClass:[NSNumber class]];
if (NO == isValid) { // not a NSNumber
errorMessage = NSLocalizedStringFromTableInBundle(@"fw_val_expectedNSNumber", @"fwLocalizedStrings" , [NSBundle mainBundle], @"expected a number here" );
code = 101;
// code = NSValidation StringTooShortError
} else { // validate NSNumber against any limit set in the model
for (NSPredicate* predicate in [mad validationPredicates]) {
NSString *predString =[predicate predicateFormat];
isValid = [predicate evaluateWithObject:*value];
NSArray *splitString = [predString componentsSeparatedByString:@" "];
NSString *expectedLimit = [splitString lastObject];
BOOL shouldBeBigger = ([predString rangeOfString:@">"].length > 0);
NSLog(@"Firstname: %@, predicate: %@, match :%d, shouldBeBigger: %d ",*value,[predicate predicateFormat], isValid, shouldBeBigger);
if (NO == isValid) {
if (shouldBeBigger) {
code = NSValidationNumberTooLargeError;
errorMessage = [NSString stringWithFormat:NSLocalizedStringFromTableInBundle(@"fw_val_NumberToBig", @"fwLocalizedStrings" , [NSBundle mainBundle], @"<key> must be at least <expectedLimit>" ), key, expectedLimit];
} else {
code = NSValidationNumberTooSmallError;
errorMessage = [NSString stringWithFormat:NSLocalizedStringFromTableInBundle(@"fw_val_NumberToSmall", @"fwLocalizedStrings" , [NSBundle mainBundle], @"<key> can't be more than <expectedLimit>" ), key, expectedLimit];
}
}
}
}
break;

case NSStringAttributeType:
isValid = [*value isKindOfClass:[NSString class]];
if (NO == isValid) { // not a NSString
errorMessage = NSLocalizedStringFromTableInBundle(@"fw_val_expectedNSString", @"fwLocalizedStrings" , [NSBundle mainBundle], @"expected a string here" );
code = 101;
} else { // validate NSString
NSArray *validationPredicatesToUse;
if ([[mad validationPredicates] count] == 0) { // no limits have been set in the model, lets get our own. Defined above
validationPredicatesToUse = [self privateValidationPredicates][key];
} else { // obtain the limits as set in the model
validationPredicatesToUse = [mad validationPredicates];
}

for (NSPredicate* predicate in validationPredicatesToUse) {
isValid = [predicate evaluateWithObject:*value]; // do the validation
NSString *predString =[predicate predicateFormat];
BOOL shouldBeLonger = ([predString rangeOfString:@">"].length > 0); // find out if is lower or upper limit
NSArray *splitString = [predString componentsSeparatedByString:@" "];
NSString *expectedLimit = [splitString lastObject]; // get limiting value i.e. from "length >= 2" get the two.
NSLog(@"Firstname: %@, predicate: %@, isValid :%d, isBigger: %d, limit: %@ ",*value,[predicate predicateFormat], isValid, shouldBeLonger, expectedLimit);
if (NO == isValid) {
if (shouldBeLonger) {
code = NSValidationStringPatternMatchingError;
errorMessage = [NSString stringWithFormat:NSLocalizedStringFromTableInBundle(@"fw_val_StringMustBeAtLeast", @"fwLocalizedStrings" , [NSBundle mainBundle], @"<key> must be at least <expectedLimit> characters" ), key, expectedLimit];
} else {
code = NSValidationStringTooShortError;
errorMessage = [NSString stringWithFormat:NSLocalizedStringFromTableInBundle(@"fw_val_StringCantBeMore", @"fwLocalizedStrings" , [NSBundle mainBundle], @"<key> can't be more than <expectedLimit> characters" ), key, expectedLimit];
}
break; // this is not a switch break. We want to break out of the For..in loop
#warning validation is not covering for NSValidationStringPatternMatchingError
}
}
}


break; // this is switch break
case NSDateAttributeType:
isValid = [*value isKindOfClass:[NSDate class]];
break;
case NSDecimalAttributeType:
isValid = [*value isKindOfClass:[NSDecimalNumber class]];
break;

default:
//NSUndefinedAttributeType, NSBinaryDataAttributeType, NSTransformableAttributeType, NSObjectIDAttributeType
isValid = NO;
break;
}
}

if (outError && errorMessage) {
NSDictionary *userInfo = @{ NSLocalizedDescriptionKey : errorMessage };
NSError *error = [[NSError alloc] initWithDomain:@"test"
Expand All @@ -48,6 +122,43 @@ - (BOOL)validateFirstName:(id *)ioValue error:(NSError **)outError {
}

return isValid;
}

- (BOOL)validateFirstName:(id *)ioValue error:(NSError **)outError {
NSLog(@"[<%@ %p> %@ line= %d] *ioValue= %@", [self class], self, NSStringFromSelector(_cmd), __LINE__, *ioValue);
NSLog(@"[<%@ %p> %@ line= %d] *outError= %@", [self class], self, NSStringFromSelector(_cmd), __LINE__, *outError);
return YES;
// firstName's validation is not specified in the model editor, it's specified here.
// field width: min 2, max 10
#warning validateFirstName has been commented
// BOOL isValid = YES;
// NSString *firstName = *ioValue;
// NSString *errorMessage;
// NSInteger code;
//
// if (firstName.length < 2) {
//
// errorMessage = @"First Name must be at least 2 characters.";
// code = NSValidationStringTooShortError;
// isValid = NO;
//
// } else if (firstName.length > 10) {
//
// errorMessage = @"First Name can't be more than 10 characters.";
// code = NSValidationStringTooLongError;
// isValid = NO;
//
// }
//
// if (outError && errorMessage) {
// NSDictionary *userInfo = @{ NSLocalizedDescriptionKey : errorMessage };
// NSError *error = [[NSError alloc] initWithDomain:@"test"
// code:code
// userInfo:userInfo];
// *outError = error;
// }
//
// return isValid;

}

Expand Down
27 changes: 27 additions & 0 deletions CoreDataValidationTest/fwLocalizedStrings.strings
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/* fwLocalizedStrings.strings
CoreDataValidationTest

Created by Olaf on 14.03.14.
Copyright (c) 2014 Murray Sagal. All rights reserved. */

/* number is to big */
"fw_val_NumberToBig" = "%1@ should be smaller than %2@";

/* number is to small */
"fw_val_NumberToSmall" = "%1@ should be bigger than %2@";

/* <key> can't be more than <expectedLimit> characters */
"fw_val_StringCantBeMore" = "%1@ can't be more than %2@ characters";

/* <key> must be at least <expectedLimit> characters */
"fw_val_StringMustBeAtLeast" = "%1@ must be at least %2@ characters";

/* expected a number here */
"fw_val_expectedNSNumber" = "Please enter a number";

/* expected a string here */
"fw_val_expectedNSString" = "Please enter a string";

/* did not expected a nil value */
"fw_val_expectedNoNil" = "Please enter a value";