You are here

location_search.module in Location 5.3

Location search interface.

File

contrib/location_search/location_search.module
View source
<?php

/**
 * @file
 * Location search interface.
 */

/**
 * Implementation of hook_menu().
 */
function location_search_menu($may_cache) {
  if ($may_cache) {
    $items[] = array(
      'path' => 'admin/settings/location/search',
      'title' => t('Search options'),
      'description' => t('Settings for Location Search module'),
      'callback' => 'drupal_get_form',
      'callback arguments' => array(
        'location_search_admin_settings',
      ),
      'access' => user_access('administer site configuration'),
      'type' => MENU_LOCAL_TASK,
      'weight' => 5,
    );
    return $items;
  }
}

/**
 * Callback for admin settings form.
 */
function location_search_admin_settings() {
  require_once drupal_get_path('module', 'location_search') . '/location_search.admin.inc';
  return _location_search_admin_settings();
}

/**
 * Implementation of hook_search(). (forwarded from location.module)
 */
function _location_search($op = 'search', $keys = null) {
  switch ($op) {
    case 'name':
      return t('Locations');
    case 'reset':
      db_query('DELETE FROM {location_search_work}');
      db_query('INSERT INTO {location_search_work} (lid) (SELECT lid FROM {location})');
      break;
    case 'status':
      $total = db_result(db_query('SELECT COUNT(lid) FROM {location}'));
      $remaining = db_result(db_query('SELECT COUNT(lid) FROM {location_search_work}'));
      return array(
        'remaining' => $remaining,
        'total' => $total,
      );
    case 'search':
      $proximity = FALSE;
      $arguments1 = array();
      $conditions1 = '1 = 1';

      // This gets rewritten for proximity searches.
      $select2 = 'i.relevance AS score';
      $join2 = '';
      $sort_parameters = 'ORDER BY score DESC';
      if ($country = search_query_extract($keys, 'country')) {
        $countries = array();
        foreach (explode(',', $country) as $c) {
          $countries[] = "l.country = '%s'";
          $arguments1[] = $c;
        }
        $conditions1 .= ' AND (' . implode(' OR ', $countries) . ')';
        $keys = search_query_insert($keys, 'country');
      }
      if ($province = search_query_extract($keys, 'province')) {
        $provinces = array();
        foreach (explode(',', $province) as $p) {
          $provinces[] = "l.province = '%s'";
          $arguments1[] = $p;
        }
        $conditions1 .= ' AND (' . implode(' OR ', $provinces) . ')';
        $keys = search_query_insert($keys, 'province');
      }
      if ($city = search_query_extract($keys, 'city')) {
        $conditions1 .= " AND (l.city = '%s')";
        $arguments1[] = $city;
        $keys = search_query_insert($keys, 'city');
      }
      if ($from = search_query_extract($keys, 'from')) {

        // Set up a proximity search.
        $proximity = TRUE;
        list($lat, $lon, $dist, $unit) = explode(',', $from);
        $distance_meters = _location_convert_distance_to_meters($dist, $unit);

        // MBR query to make it easier on the database.
        $conditions1 .= " AND l.latitude > %f AND l.latitude < %f AND l.longitude > %f AND l.longitude < %f";
        $latrange = earth_latitude_range($lon, $lat, $distance_meters);
        $lonrange = earth_longitude_range($lon, $lat, $distance_meters);
        $arguments1[] = $latrange[0];
        $arguments1[] = $latrange[1];
        $arguments1[] = $lonrange[0];
        $arguments1[] = $lonrange[1];

        // Distance query to finish the job.
        $conditions1 .= ' AND ' . earth_distance_sql($lon, $lat) . ' < %f';
        $arguments1[] = $distance_meters;

        // Override the scoring mechanism to use calculated distance
        // as the scoring metric.
        $join2 = 'INNER JOIN {location} l ON i.sid = l.lid';
        $select2 = earth_distance_sql($lon, $lat, 'l') . ' AS distance';
        $sort_parameters = 'ORDER BY distance ASC';
        $keys = search_query_insert($keys, 'from');
      }
      $lids = array();
      if (empty($keys)) {

        // Non-fulltext search. We will be skipping the built-in logic.
        $add = '';
        if ($proximity) {
          $add = ', ' . earth_distance_sql($lon, $lat, 'l') . ' AS distance';
        }
        $query = "SELECT l.lid{$add} FROM {location} l WHERE {$conditions1}";
        $countquery = "SELECT COUNT(*) FROM {location} l WHERE {$conditions1}";
        $result = pager_query($query, 10, 0, $countquery, $arguments1);
        while ($row = db_fetch_object($result)) {
          $lids[] = $row->lid;
        }
      }
      else {

        // Fuzzy search -- Use the fulltext routines against the indexed locations.
        $find = do_search($keys, 'location', 'INNER JOIN {location} l ON l.lid = i.sid ', $conditions1 . (empty($where1) ? '' : ' AND ' . $where1), $arguments1, $select2, $join2, array(), $sort_parameters);
        foreach ($find as $item) {
          $lids[] = $item->sid;
        }
      }
      $results = array();
      foreach ($lids as $lid) {
        $loc = location_load_location($lid);
        $result = db_query('SELECT nid, uid FROM {location_instance} WHERE lid = %d', $lid);
        $instance_links = array();
        while ($row = db_fetch_array($result)) {
          $instance_links[] = $row;
        }
        location_invoke_locationapi($instance_links, 'instance_links');
        $results[] = array(
          'links' => $instance_links,
          'location' => $loc,
        );
      }
      return $results;
  }
}
function location_search_form_alter($form_id, &$form) {
  if ($form_id == 'search_form' && arg(1) == 'location' && user_access('use advanced search')) {

    // @@@ Cache this.
    $result = db_query('SELECT DISTINCT country FROM {location}');
    $countries = array(
      '' => '',
    );
    while ($row = db_fetch_array($result)) {
      if (!empty($row['country'])) {
        $country = $row['country'];
        location_standardize_country_code($country);
        $countries[$country] = location_country_name($country);
      }
    }
    ksort($countries);
    drupal_add_js(drupal_get_path('module', 'location') . '/location_autocomplete.js');

    // Keyword boxes:
    $form['advanced'] = array(
      '#type' => 'fieldset',
      '#title' => t('Advanced search'),
      '#collapsible' => TRUE,
      '#collapsed' => TRUE,
      '#attributes' => array(
        'class' => 'search-advanced',
      ),
    );
    $form['advanced']['country'] = array(
      '#type' => 'select',
      '#title' => t('Country'),
      '#options' => $countries,
      // Used by province autocompletion js.
      '#attributes' => array(
        'class' => 'location_auto_country',
      ),
    );
    $form['advanced']['province'] = array(
      '#type' => 'textfield',
      '#title' => t('State/Province'),
      '#autocomplete_path' => 'location/autocomplete/' . variable_get('location_default_country', 'us'),
      // Used by province autocompletion js.
      '#attributes' => array(
        'class' => 'location_auto_province',
      ),
    );
    $form['advanced']['city'] = array(
      '#type' => 'textfield',
      '#title' => t('City'),
    );
    $form['advanced']['proximity'] = array(
      '#type' => 'fieldset',
      '#collapsible' => TRUE,
      '#collapsed' => TRUE,
      '#title' => t('Proximity'),
    );
    $form['advanced']['proximity']['map'] = array();
    if (variable_get('location_search_map_address', 1)) {
      $form['advanced']['proximity']['locpick_address'] = array(
        '#type' => 'textfield',
        '#title' => t('Locate Address'),
      );
    }
    $form['advanced']['proximity']['latitude'] = array(
      '#type' => 'textfield',
      '#title' => t('Latitude'),
    );
    $form['advanced']['proximity']['longitude'] = array(
      '#type' => 'textfield',
      '#title' => t('Longitude'),
    );
    $form['advanced']['proximity']['distance'] = array(
      '#type' => 'fieldset',
      '#title' => t('Distance'),
    );
    $form['advanced']['proximity']['distance']['distance'] = array(
      '#type' => 'textfield',
      '#size' => 5,
      '#maxlength' => 5,
    );
    $form['advanced']['proximity']['distance']['units'] = array(
      '#type' => 'select',
      '#options' => array(
        'mi' => t('mi'),
        'km' => t('km'),
      ),
    );
    $form['advanced']['submit'] = array(
      '#type' => 'submit',
      '#value' => t('Advanced search'),
      '#prefix' => '<div class="action">',
      '#suffix' => '</div>',
    );
    if (variable_get('location_search_map', 1)) {
      $map_fields = array(
        'latitude' => 'latitude',
        'longitude' => 'longitude',
      );
      if (variable_get('location_search_map_address', 1)) {
        $map_fields['address'] = 'locpick_address';
      }
      if (module_exists('gmap')) {
        $form['advanced']['proximity']['map']['#value'] = gmap_set_location(variable_get('location_search_map_macro', '[gmap |behavior=+collapsehack]'), $form['advanced']['proximity'], $map_fields);
      }
    }
    $form['#validate']['location_search_validate'] = array();
  }
}
function location_search_validate($form_id, $form_values, $form) {

  // Initialise using any existing basic search keywords.
  $keys = $form_values['processed_keys'];
  if (!empty($form_values['country'])) {
    $keys = search_query_insert($keys, 'country', $form_values['country']);
    if (!empty($form_values['province'])) {
      $keys = search_query_insert($keys, 'province', location_province_code($form_values['country'], $form_values['province']));
    }
  }
  if (!empty($form_values['city'])) {
    $keys = search_query_insert($keys, 'city', $form_values['city']);
  }
  if (!empty($form_values['latitude']) && !empty($form_values['longitude']) && !empty($form_values['distance'])) {
    $keys = search_query_insert($keys, 'from', $form_values['latitude'] . ',' . $form_values['longitude'] . ',' . $form_values['distance'] . ',' . $form_values['units']);
  }
  if (!empty($keys)) {
    form_set_value($form['basic']['inline']['processed_keys'], trim($keys));
  }
}

/**
 * Implementation of hook_update_index().
 */
function location_update_index() {
  $limit = (int) variable_get('search_cron_limit', 100);
  $result = db_query_range('SELECT lid FROM {location_search_work}', 0, $limit);
  while ($row = db_fetch_object($result)) {
    $loc = location_load_location($row->lid);
    $text = theme('location', $loc, array());

    // @@@ hide?
    search_index($row->lid, 'location', $text);
    db_query('DELETE FROM {location_search_work} WHERE lid = %d', $row->lid);
  }
}

/**
 * Implementation of hook_locationapi().
 */
function location_search_locationapi(&$obj, $op, $a3 = NULL, $a4 = NULL, $a5 = NULL) {
  if ($op == 'save') {

    // Ensure the changed location is in our work list.
    db_query('DELETE FROM {location_search_work} WHERE lid = %d', $obj['lid']);
    db_query('INSERT INTO {location_search_work} (lid) VALUES (%d)', $obj['lid']);
  }
  if ($op == 'delete') {
    search_wipe($obj['lid'], 'location');
  }
}

/**
 * Implementation of hook_search_page().
 * (It's named location_search_page because the $type is 'location'.)
 */
function location_search_page($rows) {
  return theme('search_results_location', $rows, 'location');
}
function template_preprocess_search_result_location(&$variables) {
  $result = $variables['result'];
  $variables['links_raw'] = array();
  foreach ($result['links'] as $link) {
    if (isset($link['title']) && isset($link['href'])) {
      $variables['links_raw'][] = $link;
    }
  }
  $variables['location_raw'] = $result['location'];
  $variables['location'] = theme('location', $result['location'], array());

  // @@@ hide?
  $variables['links'] = theme('links', $variables['links_raw']);

  // Provide alternate search result template.
  $variables['template_files'][] = 'search-result-' . $variables['type'];
}

/////////////// Theme compatibility wrappers //////////////////

// Needed due to the lack of the theme registry in Drupal 5. //

///////////////////////////////////////////////////////////////

// Compatibility preprocessor. Shouldn't be needed in 6.
function template_preprocess_search_results_location(&$variables) {
  $variables['search_results'] = '';
  foreach ($variables['results'] as $result) {
    $variables['search_results'] .= theme('search_result_location', $result, $variables['type']);
  }
  $variables['pager'] = theme('pager', NULL, 10, 0);

  // Provide alternate search results template.
  $variables['template_files'][] = 'search-results-' . $variables['type'];
}
function theme_search_results_location($results, $type) {
  $variables = array(
    'results' => $results,
    'type' => $type,
  );
  return _location_render('search_results_location', $variables, 'location_search');
}
function theme_search_result_location($result, $type) {
  $variables = array(
    'result' => $result,
    'type' => $type,
  );
  return _location_render('search_result_location', $variables, 'location_search');
}

Functions

Namesort descending Description
location_search_admin_settings Callback for admin settings form.
location_search_form_alter
location_search_locationapi Implementation of hook_locationapi().
location_search_menu Implementation of hook_menu().
location_search_page Implementation of hook_search_page(). (It's named location_search_page because the $type is 'location'.)
location_search_validate
location_update_index Implementation of hook_update_index().
template_preprocess_search_results_location
template_preprocess_search_result_location
theme_search_results_location
theme_search_result_location
_location_search Implementation of hook_search(). (forwarded from location.module)