This is sort of a two part question, but here's my PHP code below and I want to sort the business_hours by day in ascending order (0,1,...6). Is this easier in PHP or iOS (this is written for integration into an iOS app)?
Also, sidenote, my iOS developer says he has issues when returning the locations array dictionary like the one below. He'd rather have locations as a numbered array (JSON for [{},{},...] instead of what I have as {},{},...), but the issue is I simply can't find a way in PHP to do that for this application requirement. I specifically need to use array keys for adding the business hours to its corresponding location. I am doing a join of three tables to grab business hours and location id, so that the location id for the business hours matches the location id of the location itself; that seems to be the only way to get the two arrays to join for the JSON output array to work... You can see below, but let me know if I am wrong or if it would be easier for my iOS developer to just learn how to iterate through and return all array values for a multidimensional, associative array with keys. Please advise!
if ($stmt = $dbh->prepare($query)) {
// initialise an array for the results
$result = array();
if ( $stmt->execute(array($lat,$lat,$lng,$rest_price,$eat_in,$take_out,$delivery)) ) {
// loop through all values
while ( $row = $stmt->fetch(PDO::FETCH_ASSOC) ) {
// Have we seen this menu before? If not, add it to the array
if ( !isset($result['locations'][$row['rest_id']]) ) {
$result['locations'][$row['rest_id']] = array(
'rest_id' => $row['rest_id'],
'user_id' => $row['user_id'],
'rest_name' => $row['rest_name'],
'lat' => $row['lat'],
'lng' => $row['lng'],
'rest_price' => $row['rest_price'],
'rest_rating' => $row['rest_rating'],
'rest_genre' => $row['rest_genre'],
'eat_in' => $row['eat_in'],
'take_out' => $row['take_out'],
'delivery' => $row['delivery'],
'rest_img' => $row['rest_img'],
'user_img' => $row['user_img'],
'business_hours' => array()
);
}
// Add the ingredient.
// remove all NULL, FALSE and Empty Strings but leave 0 (zero) values
$result['locations'][$row['rest_id']]['business_hours'][] = array_filter(array(
'day' => $row['day'],
'open_time' => $row['open_time'],
'close_time' => $row['close_time']
), 'strlen');
}
// print results if not null
if( $result != null ) {
// print success. no error.
$result['error'] .= '';
echo json_encode($result);
//print_r($result);
} else {
echo json_encode(array('error' => 'No locations exist in your area'));
}
Array
(
[locations] => Array
(
[67] => Array
(
[rest_id] => 67
[user_id] => 19
[rest_name] => The Ninja
[lat] => 34.1516
[lng] => -106.685591
[rest_price] => 2
[rest_rating] => 3.5
[rest_genre] => Japanese
[eat_in] => 1
[take_out] => 1
[delivery] => 1
[rest_img] => 88/image11.png
[user_img] => image595.png
[business_hours] => Array
(
[0] => Array
(
[day] => 4
[open_time] => 09:00:00
[close_time] => 16:30:00
)
[1] => Array
(
[day] => 1
[open_time] => 10:00:00
[close_time] => 17:00:00
)
[2] => Array
(
[day] => 6
[open_time] => 12:00:00
[close_time] => 18:00:00
)
[3] => Array
(
[day] => 3
[open_time] => 10:00:00
[close_time] => 17:00:00
)
[4] => Array
(
[day] => 0
[open_time] => 00:00:00
[close_time] => 00:00:00
)
[5] => Array
(
[day] => 5
[open_time] => 10:00:00
[close_time] => 17:00:00
)
[6] => Array
(
[day] => 2
[open_time] => 10:00:00
[close_time] => 17:00:00
)
)
)// more arrays occur after this...
)
[error] =>
)
JSON
{"locations":{"67":{"rest_id":"67","user_id":"19","rest_name":"The Ninja","lat":"","lng":"","rest_price":"2","rest_rating":"3.5","rest_genre":"Japanese","eat_in":"1","take_out":"1","delivery":"1","rest_img":"","user_img":"","business_hours":[{"day":"6","open_time":"12:00:00","close_time":"18:00:00"},{"day":"3","open_time":"10:00:00","close_time":"17:00:00"},{"day":"0","open_time":"00:00:00","close_time":"00:00:00"},{"day":"5","open_time":"10:00:00","close_time":"17:00:00"},{"day":"2","open_time":"10:00:00","close_time":"17:00:00"},{"day":"4","open_time":"09:00:00","close_time":"16:30:00"},{"day":"1","open_time":"10:00:00","close_time":"17:00:00"}]},{},...},"error":""}
Well, that took forever (partly because the json string wasn't valid since it had a ...
in it, but w/e).
Your developer prefers an array-of-dictionaries like this {"locations":[{},{},...],"error":""}
instead of a dictionary-of-dictionaries like this {"locations":{"67":{},"89":{},...} ,"error":""}
because the array-of-dictionaries fits nicely into the iOS table view paradigm. However, it's only one line of code to convert the dictionary-of-dictionaries into an array-of-dictionaries, e.g.
NSArray *locationAllValues = [locationDictionary allValues];
So the only question is one of performance. Do you force the server to do more work to generate the preferred format, or do you let the mobile device do some of the work?
When parsing the JSON data, I recommend using the NSJSONReadingMutableContainers
option so that the arrays and dictionaries are mutable. That makes it easier to sort the day
arrays. And yes, it's easy to sort the arrays in iOS. Here's a full set of code that creates an array of dictionaries from the input JSON. The input to the code is an NSData
object that contains the JSON string downloaded from the network. The array of dictionaries is sorted by the rest_id
, and within each dictionary, the array of business_hours
is sorted by day
.
Note that the code has no error checking, other than checking for nil
after the call to JSONObjectWithData
. This is just proof of concept, not production code. Use at your own risk.
- (NSArray *)parseAndSortJsonResponse:(NSData *)data
{
NSDictionary *jsonData = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
if ( !jsonData )
{
NSLog( @"Invalid JSON string" );
return( nil );
}
NSMutableDictionary *locationDictionary = jsonData[@"locations"];
NSArray *locationAllValues = [locationDictionary allValues];
NSArray *locationsArray = [locationAllValues sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2)
{
NSDictionary *d1 = obj1;
NSDictionary *d2 = obj2;
int v1 = [d1[@"rest_id"] intValue];
int v2 = [d2[@"rest_id"] intValue];
if ( v1 < v2 )
return( NSOrderedAscending );
else if ( v1 > v2 )
return( NSOrderedDescending );
else
return( NSOrderedSame );
}];
for ( NSMutableDictionary *location in locationsArray )
{
NSArray *array = location[@"business_hours"];
NSArray *sorted = [array sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2)
{
NSDictionary *d1 = obj1;
NSDictionary *d2 = obj2;
int v1 = [d1[@"day"] intValue];
int v2 = [d2[@"day"] intValue];
if ( v1 < v2 )
return( NSOrderedAscending );
else if ( v1 > v2 )
return( NSOrderedDescending );
else
return( NSOrderedSame );
}];
[location setObject:sorted forKey:@"business_hours"];
}
NSLog( @"%@", locationsArray );
return( locationsArray );
}