// // HRObject.m // // Created by Chad Podoski on 11/23/09. // Copyright 2009 Shacked Software. All rights reserved. // #import "HRObject.h" #import "AppDelegate_Shared.h" @interface HRObject (Private) + (void)populateObject:(id)object withDictionary:(NSDictionary *)dict; + (id)managedObjectForEntity:(NSString *)entity uuid:(NSString *)uuid; @end @implementation HRObject + (void)initialize { [self setDelegate:self]; [self setBaseURL:[NSURL URLWithString:SSBaseApiUrl]]; [self setFormat:HRDataFormatJSON]; //NSDictionary *params = [NSDictionary dictionaryWithObject:@"1234567" forKey:@"api_key"]; //[self setDefaultParams:params]; } /** * Called when the resource was succeffully fetched and encoded * * @param connection The connection object for the current request * @param resource The converted objc representation of the response data returned by the server. * @param object Any custom object you passed in while making the request. */ + (void)restConnection:(NSURLConnection *)connection didReturnResource:(id)resource object:(id)object { /* Converts from the HTTPRiot model class to Core Data Model class and CRUD in managed object context */ NSMutableSet *responseSet = [self convertToCoreData:resource]; if (!IsEmpty(object) && [object respondsToSelector:@selector(httpRiotResponseReceived:)]) { [object performSelector:@selector(httpRiotResponseReceived:) withObject:responseSet]; } } /** * Called when the connection receieves any type of response * * @param connection The connection object for the current request * @param response The response object returned by the server. * @param object Any custom object you passed in while making the request. */ + (void)restConnection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)response object:(id)object { NSLog(@"RESPONSE STATUS WAS:%i", [response statusCode]); } /** * Called when the connection fails in situations where the server is not available, etc. * * @param connection The connection object for the current request * @param error The error returned by the connection. * @param object Any custom object you passed in while making the request. */ + (void)restConnection:(NSURLConnection *)connection didFailWithError:(NSError *)error object:(id)object { AlertWithMessage([error localizedDescription]); } /** * Called when the connection receieves a statusCode that isn't a success code. * * @param connection The connection object for the current request * @param error The error returned by the connection. * @param response The response object returned by the server. * @param object Any custom object you passed in while making the request. */ + (void)restConnection:(NSURLConnection *)connection didReceiveError:(NSError *)error response:(NSHTTPURLResponse *)response object:(id)object { AlertWithMessage([error localizedDescription]); } /** * Called when the HRFormatter recieved an error parsing the response data. * * @param connection The connection object for the current request * @param error The parser error returned by the formatter. * @param body A string representation of the response body returned by the server. * @param object Any custom object you passed in while making the request. */ + (void)restConnection:(NSURLConnection *)connection didReceiveParseError:(NSError *)error responseBody:(NSString *)body object:(id)object { AlertWithMessage([error localizedDescription]); } #pragma mark - Core Data Methods + (NSMutableSet *)convertToCoreData:(id)resource { NSMutableSet *result; /* Determine if we are dealing with a single object or an array of objects */ if ([resource isKindOfClass:[NSDictionary class]]) { NSDictionary *dict = (NSDictionary *)resource; NSString *entity = [dict valueForKey:SSEntityKey]; NSString *uuid = [dict valueForKey:SSUuidKey]; /* Make sure object an entity name and an uuid */ if (!IsEmpty(entity) && !IsEmpty(uuid)) { result = [NSMutableSet setWithCapacity:1]; /* Class name needs to be prefixed with class prefix for this project */ id object = [self managedObjectForEntity:entity uuid:uuid]; // NSLog(@"******************************"); // NSLog(@"BEFORE %@", object); [self populateObject:object withDictionary:resource]; // NSLog(@"------------------------------"); // NSLog(@"AFTER %@", object); [result addObject:object]; } }else if ([resource isKindOfClass:[NSArray class]]) { result = [NSMutableSet setWithCapacity:[(NSArray *)resource count]]; for (id object in resource) { [result unionSet:[self convertToCoreData:object]]; } } return result; } + (void)populateObject:(id)object withDictionary:(NSDictionary *)dict { NSArray *keys = [dict allKeys]; for (NSString *key in keys) { id value = [dict valueForKey:key]; key = [key capitalizedString]; key = [key stringByReplacingOccurrencesOfString:@"_" withString:@""]; /* An NSArray value indicates that this is a relation */ if ([value isKindOfClass:[NSArray class]]) { /* Recursive build the relation */ NSMutableSet *relationSet = [self convertToCoreData:value]; /* Add relation to object */ SEL selector = NSSelectorFromString([NSString stringWithFormat:@"add%@:", key]); if ([object respondsToSelector:selector]) { [object performSelector:selector withObject:relationSet]; } } /* A NSDictionary indicate a 1-to-1 relationship from Django Piston */ else if ([value isKindOfClass:[NSDictionary class]]) { NSMutableSet *relationSet = [self convertToCoreData:value]; if (!IsEmpty(relationSet) && [relationSet count] == 1) { /* Add object to model */ SEL selector = NSSelectorFromString([NSString stringWithFormat:@"set%@:", key]); if ([object respondsToSelector:selector]) { [object performSelector:selector withObject:[relationSet anyObject]]; } } } /* It is a simple attribute */ else { SEL setter = NSSelectorFromString([NSString stringWithFormat:@"set%@:", key]); if ([object respondsToSelector:setter]) { if (!IsEmpty(value) && ![value isEqual:[NSNull null]]) { if ([value isKindOfClass:[NSString class]]) { if (![value isEqualToString:@""]) { /* Just lowercase the first character */ key = [key stringByReplacingCharactersInRange:NSMakeRange(0,1) withString:[[key substringToIndex:1] lowercaseString]]; SEL getter = NSSelectorFromString(key); if ([object respondsToSelector:getter]) { NSManagedObject *mObject = (NSManagedObject*)object; NSPropertyDescription *propDesc = [[[[mObject class] entityDescription] propertiesByName] objectForKey:key]; if ([propDesc isMemberOfClass:[NSAttributeDescription class]]) { NSAttributeDescription *attribDesc = (NSAttributeDescription*)propDesc; if ([attribDesc attributeType] == NSDateAttributeType) { NSDate *date = [NSDate dateFromString:value]; if (!IsEmpty(date)) { [object performSelector:setter withObject:date]; } } else if ([attribDesc attributeType] == NSDecimalAttributeType) { NSDecimalNumber *number = [NSDecimalNumber decimalNumberWithString:value]; if (!IsEmpty(number)) { [object performSelector:setter withObject:number]; } } else { [object performSelector:setter withObject:value]; } } } } } else { [object performSelector:setter withObject:value]; } } } } } } + (id)managedObjectForEntity:(NSString *)entity uuid:(NSString *)uuid { id object; NSManagedObjectContext *moc = [(AppDelegate_Shared*)[[UIApplication sharedApplication] delegate] managedObjectContext]; NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease]; [request setEntity:[NSEntityDescription entityForName:entity inManagedObjectContext:moc]]; [request setPredicate:[NSPredicate predicateWithFormat:@"uuid = %@", uuid]]; NSError *error = nil; NSArray *results = [moc executeFetchRequest:request error:&error]; if (error) { NSLog(@"%@", error); } else if (!IsEmpty(results)) { object = [results objectAtIndex:0]; } else { object = [NSEntityDescription insertNewObjectForEntityForName:entity inManagedObjectContext:moc];; } return object; } @end