You are here

function location_search_search_execute in Location 7.5

Same name and namespace in other branches
  1. 7.3 contrib/location_search/location_search.module \location_search_search_execute()

Implements hook_search_execute().

File

contrib/location_search/location_search.module, line 85
Location search interface.

Code

function location_search_search_execute($keys = NULL, $conditions = NULL) {
  $proximity = FALSE;
  $lids = array();

  // Determine whether this is a fulltext search or not.
  $fulltext = $keys;
  $fulltext = search_expression_insert($fulltext, 'country');
  $fulltext = search_expression_insert($fulltext, 'province');
  $fulltext = search_expression_insert($fulltext, 'city');
  $fulltext = search_expression_insert($fulltext, 'from');
  $fulltext = empty($fulltext) ? FALSE : TRUE;
  if ($fulltext) {

    // Fuzzy search -- Use the fulltext routines against the indexed locations.
    $query = db_select('search_index', 'i')
      ->extend('SearchQuery')
      ->extend('PagerDefault');
    $query
      ->join('location', 'l', 'l.lid = i.sid');
    $query
      ->searchExpression($keys, 'node');

    // Insert special keywords.
    $query
      ->setOption('country', 'l.country');
    $query
      ->setOption('province', 'l.province');
    $query
      ->setOption('city', 'l.city');

    // setOption() can't handle the complexity of this so do it manually.
    if ($value = search_expression_extract($keys, 'from')) {

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

      // MBR query to make it easier on the database.
      $latrange = earth_latitude_range($lon, $lat, $distance_meters);
      $lonrange = earth_longitude_range($lon, $lat, $distance_meters);
      $query
        ->condition('l.latitude', array(
        $latrange[0],
        $latrange[1],
      ), 'BETWEEN');
      $query
        ->condition('l.longitude', array(
        $lonrange[0],
        $lonrange[1],
      ), 'BETWEEN');

      // Distance query to finish the job.
      $query
        ->where(earth_distance_sql($lon, $lat) . ' < ' . $distance_meters);

      // Override the scoring mechanism to use calculated distance
      // as the scoring metric.
      $query
        ->addExpression(earth_distance_sql($lon, $lat, 'l'), 'distance');
      $query
        ->orderBy('distance', 'DESC');
      $query->searchExpression = search_expression_insert($query->searchExpression, 'from');
    }

    // Only continue if the first pass query matches.
    if (!$query
      ->executeFirstPass()) {
      return array();
    }
  }
  else {
    $query = db_select('location', 'l')
      ->extend('PagerDefault');

    // sid is the alias so that our results match the fulltext search results.
    $query
      ->addField('l', 'lid', 'sid');

    // Insert special keywords.
    if ($value = search_expression_extract($keys, 'country')) {
      $query
        ->condition('l.country', $value);
    }
    if ($value = search_expression_extract($keys, 'province')) {
      $query
        ->condition('l.province', $value);
    }
    if ($value = search_expression_extract($keys, 'city')) {
      $query
        ->condition('l.city', $value);
    }

    // This is almost duplicated from the fulltext search above because if it
    // were refactored out it would make the code a little less clean and a
    // little harder to understand.
    if ($value = search_expression_extract($keys, 'from')) {

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

      // MBR query to make it easier on the database.
      $latrange = earth_latitude_range($lon, $lat, $distance_meters);
      $lonrange = earth_longitude_range($lon, $lat, $distance_meters);
      $query
        ->condition('l.latitude', array(
        $latrange[0],
        $latrange[1],
      ), 'BETWEEN');
      $query
        ->condition('l.longitude', array(
        $lonrange[0],
        $lonrange[1],
      ), 'BETWEEN');

      // Distance query to finish the job.
      $query
        ->where(earth_distance_sql($lon, $lat) . ' < ' . $distance_meters);

      // Override the scoring mechanism to use calculated distance
      // as the scoring metric.
      $query
        ->addExpression(earth_distance_sql($lon, $lat, 'l'), 'distance');
      $query
        ->orderBy('distance', 'DESC');
    }
  }

  // Load results.
  $found = $query
    ->limit(10)
    ->execute();
  foreach ($found as $item) {
    $lids[] = $item->sid;
  }
  $results = array();
  foreach ($lids as $lid) {
    $loc = location_load_location($lid);
    $result = db_query('SELECT nid, uid, genid FROM {location_instance} WHERE lid = :lid', array(
      ':lid' => $lid,
    ), array(
      'fetch' => PDO::FETCH_ASSOC,
    ));
    $instance_links = array();
    foreach ($result as $row) {
      $instance_links[] = $row;
    }
    location_invoke_locationapi($instance_links, 'instance_links');
    $results[] = array(
      'links' => $instance_links,
      'location' => $loc,
    );
  }
  return $results;
}