$trip['id'], 'routes' => count($trip['options']['legs']) ]); if ($id && $id>0) { $trip['options']['gid'] = $id; error_log('New parsedemail_item_advice_google.id='.$id); } else { return [NULL, 'Failed to create advice record']; } $timezones = []; $n = count($trip['options']['legs']); for ($i=0; $i<$n; $i++) { $leg = $trip['options']['legs'][$i]; $leg_id = $leg['id']; $leg_steps = $trip['options']['leg_steps'][$leg_id]; $leg_fare = $trip['options']['leg_fare'][$leg_id]; // Timezones foreach(array("departure","arrival") as $tzid) { $key1 = "${tzid}_time_zone"; $key2 = "${tzid}_timezone"; if (array_key_exists($leg[$key1],$timezones)) { $leg[$key2] = $timezones[$leg[$key1]]; } else { $tz = self::getTimezoneById($db, $leg[$key1]); $timezones[$leg[$key1]] = $tz; $leg[$key2] = $tz; } } //error_log(json_encode($leg)); list ($id, $err) = self::saveGoogleDirectionsLeg($db, [ 'parsedemail_item_advice_google_id' => $trip['options']['gid'], 'arrival_time' => $leg["arrival_time"], 'arrival_time_zone' => $leg["arrival_time_zone"], 'departure_time' => $leg["departure_time"], 'departure_time_zone' => $leg["departure_time_zone"], 'distance' => $leg["distance"], 'duration' => $leg["duration"], 'steps' => $leg["steps"], 'fare_raw' => $leg["fare_raw"], 'polyline' => self::processPolyline($leg["polyline"]) ]); if ($id && $id>0) { $old_leg_id = $leg_id; $leg_id = $id; $leg['parsedemail_item_advice_google_id'] = $trip['options']['gid']; // Legs $leg['id'] = $id; $trip['options']['legs'][$i] = $leg; // Leg steps unset($trip["options"]["leg_steps"][$old_leg_id]); $trip['options']['leg_steps'][$leg_id] = $leg_steps; // Leg fare unset($trip['options']['leg_fare'][$old_leg_id]); $trip['options']['leg_fare'][$leg_id] = $leg_fare; // ... error_log('New google_directions_legs.id='.$id); } else { self::deleteAdviceGoogle($db, $trip['options']['gid']); return [NULL, 'Failed to create leg record: '.$err]; } $m = count($leg_steps); for ($j=0; $j<$m; $j++) { $step = $leg_steps[$j]; $data = [ 'google_directions_leg_id' => $leg_id, 'distance' => $step["distance"], 'duration' => $step["duration"], 'travel_mode' => $step["travel_mode"], 'location_start_lat' => $step["location_start_lat"], 'location_start_lng' => $step["location_start_lng"], 'location_end_lat' => $step["location_end_lat"], 'location_end_lng' => $step["location_end_lng"], 'html_instructions' => $step["html_instructions"], 'polyline' => self::processPolyline($step["polyline"]) ]; list($id, $err) = self::saveGoogleDirectionsLegStep($db, $data); if ($id && $id>0) { $sid = $id; $step['sid'] = $id; $leg_steps[$j] = $step; if ($data['polyline']=="") { // We do not have a polyline - try get one... $data['id'] = $id; $data['sid'] = $sid; $polyline = self::getPolyline($db, $data); } error_log('New google_directions_leg_steps.id='.$sid); } else { self::deleteAdviceGoogle($db, $trip['options']['gid']); return [NULL, 'Failed to create leg step record']; } if (count($step)>20) { list($id, $err) = self::saveGoogleDirectionsLegStepDetail($db, [ 'google_directions_leg_step_id' => $sid, 'num_stops' => $step["num_stops"], 'line' => $step["line"], 'vehicle' => $step["vehicle"], 'departure_stop' => $step["departure_stop"], 'departure_stop_lat' => $step["departure_stop_lat"], 'departure_stop_lng' => $step["departure_stop_lng"], 'arrival_stop' => $step["arrival_stop"], 'arrival_stop_lat' => $step["arrival_stop_lat"], 'arrival_stop_lng' => $step["arrival_stop_lng"], 'headsign' => $step["headsign"], 'headway' => $step["headway"] ]); if ($id && $id>0) { $step['id'] = $id; $leg_steps[$j] = $step; error_log('New google_directions_leg_step_details.id='.$id); error_log(json_encode($step)); if (array_key_exists("fare_raw",$step)) { self::saveLegStepQuote($db, [ 'google_directions_leg_step_id' => $sid, 'name' => $step["line"], 'service' => $step["agency"], 'board' => $step["departure_stop"], 'alight' => $step["arrival_stop"], 'distance' => sprintf("%0.02f",$step["distance"]/1000), 'fare' => $step["fare"], 'fare_raw' => $step["fare_raw"], 'distance_raw' => $step["distance"] ]); } } else { self::deleteAdviceGoogle($db, $trip['options']['gid']); return [NULL, 'Failed to create leg step detail record']; } } else { error_log('Step #'.$sid.' does not have details'); } } // for $trip['options']['leg_steps'][$leg_id] = $leg_steps; } // for return [$trip, NULL]; } public function getLegStepQuotes($db, $id) { $q = "SELECT * FROM leg_step_quote WHERE google_directions_leg_step_id "; $q.= " IN (SELECT id FROM google_directions_leg_steps WHERE google_directions_leg_id=${id})"; $r = pg_query($db, $q); if ($r && pg_num_rows($r)) { $quotes = []; while ($f=pg_fetch_assoc($r)) { $quotes[] = $f; } return [$quotes, NULL]; } return [NULL, pg_last_error($db)]; } public function delete($db, $id) { $result = 0; $q = "DELETE FROM leg_step_quote WHERE google_directions_leg_step_id "; $q.= " IN (SELECT id FROM google_directions_leg_steps WHERE google_directions_leg_id "; $q.= " IN (SELECT id FROM google_directions_legs WHERE parsedemail_item_advice_google_id "; $q.= " IN (SELECT id FROM parsedemail_item_advice_google WHERE parsedemail_item_id=${id})))"; $r = pg_query($db, $q); if ($r && pg_affected_rows($r)) { $result++; } //error_log(pg_last_error()); $q = "DELETE FROM google_directions_leg_step_details WHERE google_directions_leg_step_id "; $q.= " IN (SELECT id FROM google_directions_leg_steps WHERE google_directions_leg_id "; $q.= " IN (SELECT id FROM google_directions_legs WHERE parsedemail_item_advice_google_id "; $q.= " IN (SELECT id FROM parsedemail_item_advice_google WHERE parsedemail_item_id=${id})))"; $r = pg_query($db, $q); if ($r && pg_affected_rows($r)) { $result++; } //error_log(pg_last_error()); $q = "DELETE FROM google_directions_leg_steps WHERE google_directions_leg_id "; $q.= " IN (SELECT id FROM google_directions_legs WHERE parsedemail_item_advice_google_id "; $q.= " IN (SELECT id FROM parsedemail_item_advice_google WHERE parsedemail_item_id=${id}))"; $r = pg_query($db, $q); if ($r && pg_affected_rows($r)) { $result++; } //error_log(pg_last_error()); $q = "DELETE FROM google_directions_legs WHERE parsedemail_item_advice_google_id "; $q.= " IN (SELECT id FROM parsedemail_item_advice_google WHERE parsedemail_item_id=${id})"; $r = pg_query($db, $q); if ($r && pg_affected_rows($r)) { $result++; } //error_log(pg_last_error()); $q = "DELETE FROM parsedemail_item_advice_google WHERE parsedemail_item_id=${id}"; $r = pg_query($db, $q); if ($r && pg_affected_rows($r)) { $result++; } //error_log(pg_last_error()); $q = "DELETE FROM parsedemail_item WHERE id=${id}"; $r = pg_query($db, $q); if ($r && pg_affected_rows($r)) { $result++; } //error_log(pg_last_error()); return $result; } public function deleteAdviceGoogle($db, $id) { $result = 0; $q = "DELETE FROM leg_step_quote WHERE google_directions_leg_step_id "; $q.= " IN (SELECT id FROM google_directions_leg_steps WHERE google_directions_leg_id "; $q.= " IN (SELECT id FROM google_directions_legs WHERE parsedemail_item_advice_google_id "; $q.= " IN (SELECT id FROM parsedemail_item_advice_google WHERE parsedemail_item_id=${id})))"; $r = pg_query($db, $q); if ($r && pg_affected_rows($r)) { $result++; } $q = "DELETE FROM google_directions_leg_step_details WHERE google_directions_leg_step_id IN (SELECT id FROM google_directions_leg_steps WHERE google_directions_leg_id IN (SELECT id FROM google_directions_legs WHERE parsedemail_item_advice_google_id IN (SELECT id FROM parsedemail_item_advice_google WHERE id=${id})))"; $r = pg_query($db, $q); if ($r && pg_affected_rows($r)) { $result++; } $q = "DELETE FROM google_directions_leg_steps WHERE google_directions_leg_id IN (SELECT id FROM google_directions_legs WHERE parsedemail_item_advice_google_id IN (SELECT id FROM parsedemail_item_advice_google WHERE id=${id}))"; $r = pg_query($db, $q); if ($r && pg_affected_rows($r)) { $result++; } $q = "DELETE FROM google_directions_legs WHERE parsedemail_item_advice_google_id IN (SELECT id FROM parsedemail_item_advice_google WHERE id=${id})"; $r = pg_query($db, $q); if ($r && pg_affected_rows($r)) { $result++; } $q = "DELETE FROM parsedemail_item_advice_google WHERE id=${id}"; $r = pg_query($db, $q); if ($r && pg_affected_rows($r)) { $result++; } return $result; } public function saveParsedemailItem($db, $data) { $fields = array( 'travel_date' => false, 'duration' => false, 'cost_raw' => false, 'trackedemail_item_id' => false, 'cost' => false, 'updated' => false, 'distance' => false, 'transport_provider_id' => false, 'scheduled' => false, 'travel_date_end' => false, 'dup_id' => false, 'location_start_id' => true, 'location_end_id' => true, 'private' => false ); return self::saveGeneric($db, $fields, $data, 'parsedemail_item'); } public function saveParsedemailItemAdviceGoogle($db, $data) { $fields = array( 'parsedemail_item_id' => true, 'routes' => true ); return self::saveGeneric($db, $fields, $data, 'parsedemail_item_advice_google'); } public function saveGoogleDirectionsLeg($db, $data) { $fields = array( 'parsedemail_item_advice_google_id' => true, 'arrival_time' => false, 'arrival_time_zone' => false, 'departure_time' => false, 'departure_time_zone' => false, 'distance' => false, 'duration' => false, 'steps' => false, 'fare_raw' => false, 'polyline' => false ); return self::saveGeneric($db, $fields, $data, 'google_directions_legs'); } public function saveGoogleDirectionsLegStep($db, $data) { $fields = array( 'google_directions_leg_id' => true, 'distance' => false, 'duration' => false, 'travel_mode' => false, 'location_start_lat' => false, 'location_start_lng' => false, 'location_end_lat' => false, 'location_end_lng' => false, 'html_instructions' => false, 'polyline' => false ); return self::saveGeneric($db, $fields, $data, 'google_directions_leg_steps'); } public function saveGoogleDirectionsLegStepDetail($db, $data) { $fields = array( 'google_directions_leg_step_id' => true, 'num_stops' => false, 'line' => false, 'vehicle' => false, 'departure_stop' => false, 'departure_stop_lat' => false, 'departure_stop_lng' => false, 'arrival_stop' => false, 'arrival_stop_lat' => false, 'arrival_stop_lng' => false, 'headsign' => false, 'headway' => false ); return self::saveGeneric($db, $fields, $data, 'google_directions_leg_step_details'); } public function saveLegStepQuote($db, $data) { error_log('public function saveLegStepQuote($db, $data)'); $fields = array( 'google_directions_leg_step_id' => true, 'name' => false, 'service' => false, 'board' => false, 'alight' => false, 'distance' => false, 'fare' => false, 'fare_raw' => true, 'distance_raw' => false ); return self::saveGeneric($db, $fields, $data, 'leg_step_quote'); } private function saveGeneric($db, $fields, $data, $table) { $q = "select column_name, data_type, character_maximum_length from INFORMATION_SCHEMA.COLUMNS where table_name = '${table}'"; $r = pg_query($db, $q); $columns = []; while ($f=pg_fetch_assoc($r)) { $columns[$f['column_name']] = $f; } $field_key_list = []; $field_val_list = []; foreach ($fields as $key=>$required) { if ($required && !isset($data[$key])) { return [NULL, "Missing required field '${key}'"]; } if (!isset($data[$key])) continue; $field_key_list[] = "${key}"; if (isset($columns[$key]) && ($columns[$key]["data_type"]=='integer' || $columns[$key]["data_type"]=='bigint')) { $field_val_list[] = ($data[$key]==NULL || strlen($data[$key])==0)?"NULL":((int)$data[$key]); } else { $field_val_list[] = (($data[$key]==NULL || $data[$key]=="")?"NULL":"'".pg_escape_string($data[$key])."'"); } } $q = "INSERT INTO ${table} (".implode(",",$field_key_list).") VALUES(".implode(",",$field_val_list).") RETURNING id"; //error_log($q); $r = pg_query($db, $q); if ($r && pg_num_rows($r)) { $f = pg_fetch_row($r); return [$f[0], NULL]; } return [NULL, pg_last_error($db)]; } public function processPolyline($data) { if (!is_array($data)) { return $data; } $points = []; foreach ($data as $item) { $points = array_merge($points, Polyline::decode($item)); } return Polyline::encode($points); } public function getPolyline($db, $f) { $q = "SELECT polyline FROM google_directions_leg_steps WHERE "; $q.= " location_start_lat='".$f["location_start_lat"]."' AND "; $q.= " location_start_lng='".$f["location_start_lng"]."' AND "; $q.= " location_end_lat='".$f["location_end_lat"]."' AND "; $q.= " location_end_lng='".$f["location_end_lng"]."' AND "; $q.= " polyline<>'' ORDER BY ID desc LIMIT 1"; $r = pg_query($db, $q); if ($r && pg_num_rows($r) && $polyline=pg_fetch_row($r)) { $f["polyline"] = $polyline[0]; $q = "UPDATE google_directions_leg_steps SET polyline='".pg_escape_string($f["polyline"])."' WHERE id=".$f['sid']." RETURNING *"; $r = pg_query($db, $q); // Do not quite care... return $f["polyline"]; } $res = MultiModalApi::getPolyline($f["sid"]); if (is_array($res) && isset($res["code"]) && $res["code"]==0) { if (isset($res["data"]) && isset($res["data"]["polyline"])) { return $res["data"]["polyline"]; // No need to update } } return $f["polyline"]; } public function getDate($country) { $tz = 'Asia/Singapore'; if ($country=='US') { $tz = 'America/Los_Angeles'; } $timestamp = time(); $dt = new DateTime("now", new DateTimeZone($tz)); //first argument "must" be a string $dt->setTimestamp($timestamp); //adjust the object to correct timestamp return $dt->format('Y-m-d, H:i:s'); } public function getLegTimezones($db, $id) { $departure_time_zone = 1; // Asia/Singapore $q = "SELECT departure_time_zone FROM google_directions_legs WHERE id=".((int)$id); $r = pg_query($db, $q); if ($r && pg_num_rows($r) && $f=pg_fetch_row($r)) { if (is_integer($f[0]) && $f[0]>0) { $departure_time_zone = $f[0]; } else { $q = "SELECT * FROM address_timezone WHERE lower(timezone)=lower('".$f[0]."')"; $r = pg_query($db, $q); if ($r && pg_num_rows($r) && $f=pg_fetch_row($r)) { $departure_time_zone = $f[0]; } } } $arrival_time_zone = 1; // Asia/Singapore $q = "SELECT arrival_time_zone FROM google_directions_legs WHERE id=".((int)$id); $r = pg_query($db, $q); if ($r && pg_num_rows($r) && $f=pg_fetch_row($r)) { if (is_integer($f[0]) && $f[0]>0) { $arrival_time_zone = $f[0]; } else { $q = "SELECT * FROM address_timezone WHERE lower(timezone)=lower('".$f[0]."')"; $r = pg_query($db, $q); if ($r && pg_num_rows($r) && $f=pg_fetch_row($r)) { $arrival_time_zone = $f[0]; } } } return [$departure_time_zone, $arrival_time_zone]; } public function getLegTimezonesForAdvice($db, $id) { $result = []; $q = "SELECT id FROM google_directions_legs WHERE parsedemail_item_advice_google_id=".((int)$id); $r = pg_query($db, $q); while ($f=pg_fetch_row($r)) { $result[$f[0]] = self::getLegTimezones($db, $f[0]); } return $result; } } // vi:ts=2