diff -rupN location/handlers/location_handler_argument_location_proximity.inc location_new/handlers/location_handler_argument_location_proximity.inc --- location/handlers/location_handler_argument_location_proximity.inc 1970-01-01 10:00:00.000000000 +1000 +++ handlers/location_handler_argument_location_proximity.inc 2010-06-16 01:23:07.000000000 +1000 @@ -0,0 +1,207 @@ + ($country == 'us' || $country == 'uk' ? 'mile' : 'km')); + $options['search_method'] = array('default' => 'mbr'); + $options['type'] = array('default' => 'postal'); + $options['separator'] = array('default' => '_'); + return $options; + } + + /** + * Add a form elements to select options for this argument. + */ + function options_form(&$form, &$form_state) { + parent::options_form($form, $form_state); + $form['type'] = array( + '#title' => t('Coordinate Type'), + '#type' => 'select', + '#options' => array( + 'postal' => t('Postal Code (Zipcode)'), + 'latlon' => t('Decimal Latitude and Longitude coordinates, comma delimited'), + ), + '#default_value' => $this->options['type'], + '#description' => t('Type of center point.'), + ); + + $form['separator'] = array( + '#title' => t('Separator'), + '#type' => 'textfield', + '#size' => 3, + '#default_value' => $this->options['separator'], + '#description' => t('Separator between coordinates/postcode and distance. Must not occur in the postal code.'), + '#required' => TRUE, + ); + + // Units used. + $form['search_units'] = array( + '#type' => 'select', + '#title' => t('Distance unit'), + '#options' => array( + 'km' => t('Kilometers'), + 'm' => t('Meters'), + 'mile' => t('Miles'), + 'dd' => t('Decimal degrees'), + ), + '#default_value' => $this->options['search_units'], + '#description' => t('Select the unit of distance. Decimal degrees should be comma delimited.'), + ); + + $form['search_method'] = array( + '#title' => t('Method'), + '#type' => 'select', + '#options' => array( + 'dist' => t('Circular Proximity'), + 'mbr' => t('Rectangular Proximity'), + ), + '#default_value' => $this->options['search_method'], + '#description' => t('Method of determining proximity. Please note that Circular Proximity does not work with Decimal degrees.'), + ); + } + + function options_validate($form, &$form_state) { + // It is very important to call the parent function here. + parent::options_validate($form, $form_state); + $notallowed = array('+', '?', '.', '[', ']', '{', '}', '(', ')', '/', '|', '^', '$', '#', '@', '=', ':', ';', '%', '-', ','); + if (in_array($form_state['values']['options']['separator'], $notallowed)) { + form_error($form['separator'], t('The character "' . $form_state['values']['options']['separator'] . '" is reserved or unsafe.')); + } + } + + // Used from the distance field. + function calculate_coords() { + if (!empty($this->value['latitude']) && !empty($this->value['longitude'])) { + // If there are already coordinates, there's no work for us. + return TRUE; + } + // @@@ Switch to mock location object and rely on location more? + + if ($this->options['type'] == 'postal') { + if (!isset($this->value['country'])) { + $this->value['country'] = variable_get('location_default_country', 'us'); + } + // Zip code lookup. + if (!empty($this->value['postal_code']) && !empty($this->value['country'])) { + location_load_country($this->value['country']); + $coord = location_get_postalcode_data($this->value); + if ($coord) { + $this->value['latitude'] = $coord['lat']; + $this->value['longitude'] = $coord['lon']; + } + else { + $coord = location_latlon_rough($this->value); + if ($coord) { + $this->value['latitude'] = $coord['lat']; + $this->value['longitude'] = $coord['lon']; + } + else { + return FALSE; + } + } + } + else { + return FALSE; + } + } + return TRUE; + } + + /** + * Set up the query for this argument. + * + * The argument sent may be found at $this->argument. + */ + function query() { + // Get and process argument. + if ($this->options['type'] == 'postal') { + foreach ($this->view->argument as $argument) { + if ($argument->field == 'distance') { + $arg_parts = explode($this->options['separator'], $this->view->args[$argument->position]); + if (count($arg_parts) == 3) { + $this->value['country'] = drupal_strtolower($arg_parts[0]); + $this->value['postal_code'] = $arg_parts[1]; + $this->value['search_distance'] = $arg_parts[2]; + } + else { + $this->value['postal_code'] = $arg_parts[0]; + $this->value['search_distance'] = $arg_parts[1]; + } + break; + } + } + } + else if ($this->options['type'] == 'latlon') { + foreach ($this->view->argument as $argument) { + if ($argument->field == 'distance') { + list($coords, $this->value['search_distance']) = explode($this->options['separator'], $this->view->args[$argument->position]); + list($this->value['latitude'], $this->value['longitude']) = explode(',', $coords); + break; + } + } + } + + // Coordinates available? + if (!$this->calculate_coords()) { + // Distance set? + if (!empty($this->value['search_distance'])) { + // Hmm, distance set but unable to resolve coordinates. + // Force nothing to match. + $this->query->add_where($this->options['group'], "0"); + } + return; + } + + $this->ensure_my_table(); + + $lat = $this->value['latitude']; + $lon = $this->value['longitude']; + + // search_distance + if ($this->options['search_units'] == 'dd') { + list($lat_distance, $lon_distance) = explode(',', $this->value['search_distance']); + $latrange[0] = $lat - $lat_distance; + $latrange[1] = $lat + $lat_distance; + $lonrange[0] = $lon - $lon_distance; + $lonrange[1] = $lon + $lon_distance; + } + else { + $distance = $this->value['search_distance']; + if ($this->options['search_units'] == 'm') { + $distance_meters = $distance; + } + else { + $distance_meters = _location_convert_distance_to_meters($distance, $this->options['search_units']); + } + + $latrange = earth_latitude_range($lon, $lat, $distance_meters); + $lonrange = earth_longitude_range($lon, $lat, $distance_meters); + } + + /*****FIX BEFORE COMMIT ****/ + // What is group and why do I need to set this to work?? + $this->options['group'] = 0; + + // Add MBR check (always). + // In case we go past the 180/-180 mark for longitude. + if ($lonrange[0] > $lonrange[1]) { + $where = "$this->table_alias.latitude > %f AND $this->table_alias.latitude < %f AND (($this->table_alias.longitude < 180 AND $this->table_alias.longitude > %f) OR ($this->table_alias.longitude < %f AND $this->table_alias.longitude > -180))"; + } + else { + $where = "$this->table_alias.latitude > %f AND $this->table_alias.latitude < %f AND $this->table_alias.longitude > %f AND $this->table_alias.longitude < %f"; + } + $this->query->add_where($this->options['group'], $where, $latrange[0], $latrange[1], $lonrange[0], $lonrange[1]); + + if ($this->options['search_method'] == 'dist') { + // Add radius check. + $this->query->add_where($this->options['group'], earth_distance_sql($lon, $lat, $this->table_alias) . ' < %f', $distance_meters); + } + } +} diff -rupN location/location.views.inc location_new/location.views.inc --- location/location.views.inc 2008-12-04 09:51:23.000000000 +1100 +++ location.views.inc 2010-06-16 01:15:49.000000000 +1000 @@ -51,6 +51,9 @@ function location_views_handlers() { 'location_handler_argument_location_province' => array( 'parent' => 'views_handler_argument', ), + 'location_handler_argument_location_proximity' => array( + 'parent' => 'views_handler_argument', + ), 'location_handler_field_location_address' => array( 'parent' => 'views_handler_field', ), @@ -303,6 +306,9 @@ function location_views_data() { 'sort' => array( 'handler' => 'location_handler_sort_location_distance', ), + 'argument' => array( + 'handler' => 'location_handler_argument_location_proximity', + ), 'filter' => array( 'handler' => 'location_views_handler_filter_proximity', ),