google.inc 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. <?php
  2. // $Id$
  3. /**
  4. * @file
  5. * Plugin to provide a google geocoder.
  6. */
  7. /**
  8. * Plugins are described by creating a $plugin array which will be used
  9. * by the system that includes this file.
  10. */
  11. $plugin = array(
  12. 'title' => t("Google Geocoder"),
  13. 'description' => t('Geocodes via google geocoder'),
  14. 'callback' => 'geocoder_google',
  15. 'field_types' => array('text', 'text_long', 'addressfield', 'text_with_summary', 'computed', 'taxonomy_term_reference'),
  16. 'field_callback' => 'geocoder_google_field',
  17. 'settings_callback' => 'geocoder_google_form',
  18. 'terms_of_service' => 'http://code.google.com/apis/maps/documentation/geocoding/#Limits',
  19. );
  20. /**
  21. * Process Markup
  22. */
  23. function geocoder_google($address, $options = array()) {
  24. geophp_load();
  25. $query = array(
  26. 'address' => $address,
  27. 'sensor' => 'false'
  28. );
  29. $url = url("http://maps.googleapis.com/maps/api/geocode/json", array('query' => $query));
  30. $result = drupal_http_request($url);
  31. if (isset($result->error)) {
  32. drupal_set_message(t('Error geocoding') . ' - ' . $result->code . ' ' . $result->error, 'error');
  33. return FALSE;
  34. }
  35. $data = json_decode($result->data);
  36. if ($data->status == 'OK') {
  37. $geometries = array();
  38. foreach ($data->results as $item) {
  39. // Check if we should reject these results
  40. if (isset($options['reject_results'])) {
  41. if (in_array($item->geometry->location_type, $options['reject_results'], TRUE)) {
  42. continue;
  43. }
  44. }
  45. // Construct a geoPHP Geometry depending on what type of geometry we want returned (defaults to point)
  46. if (!isset($options['geometry_type']) || $options['geometry_type'] == 'point') {
  47. $geom = new Point($item->geometry->location->lng, $item->geometry->location->lat);
  48. }
  49. elseif ($options['geometry_type'] == 'bounds') {
  50. $points = array(
  51. new Point($item->geometry->bounds->southwest->lng, $item->geometry->bounds->southwest->lat),
  52. new Point($item->geometry->bounds->southwest->lng, $item->geometry->bounds->northeast->lat),
  53. new Point($item->geometry->bounds->northeast->lng, $item->geometry->bounds->northeast->lat),
  54. new Point($item->geometry->bounds->northeast->lng, $item->geometry->bounds->southwest->lat),
  55. new Point($item->geometry->bounds->southwest->lng, $item->geometry->bounds->southwest->lat),
  56. );
  57. $geom = new Polygon(array(new LineString($points)));
  58. }
  59. elseif ($options['geometry_type'] == 'viewport') {
  60. $points = array(
  61. new Point($item->geometry->viewport->southwest->lng, $item->geometry->viewport->southwest->lat),
  62. new Point($item->geometry->viewport->southwest->lng, $item->geometry->viewport->northeast->lat),
  63. new Point($item->geometry->viewport->northeast->lng, $item->geometry->viewport->northeast->lat),
  64. new Point($item->geometry->viewport->northeast->lng, $item->geometry->viewport->southwest->lat),
  65. new Point($item->geometry->viewport->southwest->lng, $item->geometry->viewport->southwest->lat),
  66. );
  67. $geom = new Polygon(array(new LineString($points)));
  68. }
  69. // Add additional metadata to the geometry - it might be useful!
  70. $geom->data = array();
  71. $geom->data['geocoder_accuracy'] = $item->geometry->location_type;
  72. $geom->data['geocoder_formatted_address'] = $item->formatted_address;
  73. $geom->data['geocoder_address_components'] = $item->address_components;
  74. $geometries[] = $geom;
  75. }
  76. if (empty($geometries)) return;
  77. // Check if we should return all results as a compound geometry
  78. if (isset($options['all_results'])) {
  79. if ($options['all_results']) {
  80. return geoPHP::geometryReduce($geometries);
  81. }
  82. }
  83. // The connonical geometry is the first result (best guesse)
  84. $geometry = array_shift($geometries);
  85. // If there are any other geometries, these are auxiliary geometries that represent "alternatives"
  86. if (count($geometries)) $geometry->data['geocoder_alternatives'] = $geometries;
  87. return $geometry;
  88. }
  89. else {
  90. drupal_set_message(t('Error geocoding') . ' - ' . $data->status, 'error');
  91. return FALSE;
  92. }
  93. }
  94. function geocoder_google_field($field, $field_item, $options = array()) {
  95. if ($field['type'] == 'text' || $field['type'] == 'text_long' || $field['type'] == 'text_with_summary' || $field['type'] == 'computed') {
  96. return geocoder_google($field_item['value'], $options);
  97. }
  98. if ($field['type'] == 'addressfield') {
  99. $address = geocoder_widget_parse_addressfield($field_item);
  100. return geocoder_google($address, $options);
  101. }
  102. if ($field['type'] == 'taxonomy_term_reference') {
  103. $term = taxonomy_term_load($field_item['tid']);
  104. return geocoder_google($term->name);
  105. }
  106. }
  107. function geocoder_google_form($default_values = array()) {
  108. $form = array();
  109. $form['geometry_type'] = array(
  110. '#type' => 'select',
  111. '#title' => 'Geometry Type',
  112. '#options' => array(
  113. 'point' => 'Point (default)',
  114. 'bounds' => 'Bounding Box',
  115. 'viewport' => 'Viewport',
  116. ),
  117. '#default_value' => isset($default_values['geometry_type']) ? $default_values['geometry_type'] : 'point',
  118. );
  119. $form['all_results'] = array(
  120. '#type' => 'checkbox',
  121. '#title' => 'Geocode all alternative results',
  122. '#default_value' => isset($default_values['all_values']) ? $default_values['all_values'] : FALSE,
  123. '#description' => 'Often an ambiguous address (such as "Springfield USA") can result in multiple hits. By default we only return the first (best guess) result. Check this to return all results as a Multi-Geometry (MultiPoint or MultiPolygon).',
  124. );
  125. $form['reject_results'] = array(
  126. '#type' => 'checkboxes',
  127. '#title' => 'Reject Results',
  128. '#options' => array(
  129. 'APPROXIMATE' => 'APPROXIMATE: indicates that the returned result is approximate.',
  130. 'GEOMETRIC_CENTER' => 'GEOMETRIC_CENTER: indicates that the returned result is the geometric center of a result such as a polyline (for example, a street) or polygon (region).',
  131. 'RANGE_INTERPOLATED' => 'RANGE_INTERPOLATED: indicates that the returned result reflects an approximation (usually on a road) interpolated between two precise points (such as intersections). Interpolated results are generally returned when rooftop geocodes are unavailable for a street address.',
  132. 'ROOFTOP' => 'ROOFTOP: indicates that the returned result is a precise geocode for which we have location information accurate down to street address precision.',
  133. ),
  134. '#default_value' => isset($default_values['reject_results']) ? $default_values['reject_results'] : array(),
  135. '#description' => 'Reject results that do not meet a certain level of quality or precision. Check all types of results to reject.',
  136. );
  137. return $form;
  138. }