geocoder.module 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. <?php
  2. /**
  3. * @file
  4. * Module file for geocoder module.
  5. */
  6. include_once('geocoder.widget.inc');
  7. include_once('geocoder.services.inc');
  8. /**
  9. * The Geocoder API call.
  10. *
  11. * Given a handler and data, geocode the data into a geometry object using the handler.
  12. *
  13. * @param string $handler
  14. * The geocoder handler to use. Call geocoder_handler_info() to get a list
  15. *
  16. * @param mixed $data
  17. * Data to be passed into the handler for geocoding. For example a address string.
  18. *
  19. * @param array $options
  20. * Additional options to pass to the handler. Exact key / values to pass depend on the handler.
  21. *
  22. * @param int $cache_type
  23. * (optional) The type of caching to use. Defaults to 2 (static and persistent)
  24. * 0 or FALSE is no-caching at all
  25. * 1 is static-cache but no persistent-cache
  26. * 2 is both static-cache AND persistent-cache
  27. *
  28. * @pram bool $cache_reset
  29. * (optional) Empty the static-cache and re-fill the persistent-cache. Defaults to FALSE.
  30. *
  31. * @return geometry
  32. * Returns a geoPHP geometry object. Generally a Point.
  33. * See http://drupal.org/project/geoPHP and https://github.com/phayes/geoPHP/wiki/API-Reference
  34. *
  35. * @example:
  36. * geocoder('google','4925 Gair Ave, Terrace, BC');
  37. * geocoder('google','New York City',array('geometry_type' => 'bounds'));
  38. */
  39. function geocoder($handler, $data, $options = array(), $cache_type = 2, $cache_reset = FALSE) {
  40. ctools_include('plugins');
  41. static $static_cache = array();
  42. if ($cache_reset) {
  43. $static_cache = array();
  44. }
  45. if ($cache_type) {
  46. $cache_id = $handler . '_' . md5(serialize(array($data, $options)));
  47. if (!empty($static_cache[$cache_id])) {
  48. return $static_cache[$cache_id];
  49. }
  50. }
  51. $processor = ctools_get_plugins('geocoder', 'geocoder_handler', $handler);
  52. $geometry = call_user_func($processor['callback'], $data, $options);
  53. if ($cache_type) {
  54. $static_cache[$cache_id] = $geometry;
  55. }
  56. return $geometry;
  57. }
  58. /**
  59. * Implements hook_menu().
  60. */
  61. function geocoder_menu() {
  62. // Admin settings for the site.
  63. $items['admin/config/content/geocoder'] = array(
  64. 'title' => 'Geocoder settings',
  65. 'description' => 'Configuration for API keys.',
  66. 'page callback' => 'drupal_get_form',
  67. 'page arguments' => array('geocoder_admin_settings'),
  68. 'file' => 'geocoder.admin.inc',
  69. 'access arguments' => array('administer site configuration'),
  70. 'type' => MENU_NORMAL_ITEM, // optional
  71. );
  72. $items['geocoder/service/%'] = array(
  73. 'title' => 'AJAX / AJAJ geocoding service',
  74. 'description' => 'Provides basic callback for geocoding using JavaScript',
  75. 'page callback' => 'geocoder_service_callback',
  76. 'page arguments' => array(2),
  77. 'type' => MENU_CALLBACK,
  78. 'access arguments' => array(arg(2)),
  79. 'access callback' => 'geocoder_service_check_perms',
  80. );
  81. return $items;
  82. }
  83. /**
  84. * Geocoder Handler Information
  85. *
  86. * Return a list of all handlers that might geocode something for you.
  87. * Optionally you may pass a field-type and get back a list of
  88. * handlers that are compatible with that field.
  89. */
  90. function geocoder_handler_info($field_type = NULL) {
  91. ctools_include('plugins');
  92. static $handlers;
  93. if (!$handlers) {
  94. $handlers = ctools_get_plugins('geocoder', 'geocoder_handler');
  95. }
  96. if ($field_type) {
  97. $field_handlers = $handlers;
  98. foreach ($field_handlers as $i => $handler) {
  99. if (!isset($handler['field_types']) || !in_array($field_type, $handler['field_types'])) {
  100. unset($field_handlers[$i]);
  101. }
  102. }
  103. return $field_handlers;
  104. }
  105. return $handlers;
  106. }
  107. /**
  108. * Fetch geocoder handler
  109. *
  110. * Given a name, fetch the full handler definition
  111. */
  112. function geocoder_get_handler($handler_name) {
  113. $handlers = geocoder_handler_info();
  114. if (isset($handlers[$handler_name])) {
  115. return $handlers[$handler_name];
  116. }
  117. else return FALSE;
  118. }
  119. /**
  120. * Get supported field types
  121. *
  122. * Get a list of supported field types along with the processors that support them
  123. */
  124. function geocoder_supported_field_types() {
  125. $supported = array();
  126. $processors = geocoder_handler_info();
  127. foreach ($processors as $processor) {
  128. if (isset($processor['field_types'])) {
  129. foreach ($processor['field_types'] as $field_type) {
  130. $supported[$field_type][] = $processor['name'];
  131. }
  132. }
  133. }
  134. return $supported;
  135. }
  136. /**
  137. * Implementation of hook_ctools_plugin_api().
  138. */
  139. function geocoder_ctools_plugin_api() {
  140. return array('version' => 1);
  141. }
  142. /**
  143. * Implementation of hook_ctools_plugin_dierctory() to let the system know
  144. * we implement plugins.
  145. */
  146. function geocoder_ctools_plugin_directory($module, $plugin) {
  147. return 'plugins/' . $plugin;
  148. }
  149. /**
  150. * Implements hook_ctools_plugin_type
  151. */
  152. function geocoder_ctools_plugin_type() {
  153. return array(
  154. 'geocoder_handler' => array(),
  155. );
  156. }
  157. // These functions have to do with providing AJAX / AHAH
  158. // service functionality so that users can make use of
  159. // geocoder interactively via JavaScript.
  160. /**
  161. * Implements hook_permission().
  162. *
  163. * We define permissions for accessing geocoder over AJAX / services.
  164. * There is one global permission which gives access to everything,
  165. * and one permission per handler. The site-administrator can therefore
  166. * fine tune which handlers are accessible. Note that to use AJAX with
  167. * geocoder these permissions need to be set.
  168. */
  169. function geocoder_permission() {
  170. $handler_info = geocoder_handler_info();
  171. $perms = array(
  172. 'geocoder_service_all_handlers' => array(
  173. 'title' => t('Can use all Geocoder handlers through AJAX / service'),
  174. ),
  175. );
  176. foreach ($handler_info as $name => $handler) {
  177. $perms['geocoder_service_handler_' . $name] = array(
  178. 'title' => t('Can geocode using @handler through AJAX / service', array('@handler' => $handler['title'])),
  179. );
  180. }
  181. return $perms;
  182. }
  183. /**
  184. * Geocoder service check permissions
  185. *
  186. * Given a handler, check to see if the user has
  187. * permission to execute it via AJAX / services
  188. */
  189. function geocoder_service_check_perms($handler) {
  190. return (user_access('geocoder_service_all_handlers') || user_access('geocoder_service_handler_' . $handler));
  191. }
  192. /**
  193. * Page callback for AJAX / Geocoder service
  194. *
  195. * This service can be accessed at /geocoder/service/<handler>
  196. * and takes the query-parameter "data". Optinally a "output"
  197. * paramater may also be passed. "output" corresponds to
  198. * geoPHP output formats.
  199. *
  200. * Some examples:
  201. * /geocoder/service/google?data=4925 Gair Ave, Terrace, BC
  202. * /geocoder/service/wkt?data=POINT(10 10)
  203. * /geocoder/service/yahoo?data=94112&output=wkt
  204. */
  205. function geocoder_service_callback($handler) {
  206. if (!isset($_GET['data'])) {
  207. throw new Exception(t('No data parameter found'));
  208. exit();
  209. }
  210. $format = isset($_GET['output']) ? $_GET['output'] : 'json';
  211. geophp_load();
  212. geocoder_service_check_request($handler, $format);
  213. $geom = geocoder($handler, $_GET['data']);
  214. header('Content-Type: ' . geocoder_service_get_content_type($format));
  215. print $geom->out($format);
  216. exit();
  217. }
  218. /**
  219. * Get Content-Type for an output format
  220. *
  221. * Given an output format, this helper function passes
  222. * a compatible HTTP content-type to be placed in the
  223. * header.
  224. */
  225. function geocoder_service_get_content_type($format) {
  226. $types = array(
  227. 'json' => 'application/json',
  228. 'kml' => 'application/xml',
  229. 'georss' => 'application/xml',
  230. 'gpx' => 'application/xml',
  231. 'wkt' => 'text/plain',
  232. 'wkb' => 'text/plain',
  233. 'google_geocode' => 'text/plain',
  234. );
  235. return $types[$format];
  236. }
  237. /**
  238. * Geocoder Service Check Request
  239. *
  240. * Check to make sure the request to the service is valid. This
  241. * checks to make sure the handler and the format exists, and
  242. * also checks permission
  243. */
  244. function geocoder_service_check_request($handler, $format, $check_ac = TRUE) {
  245. if (!geocoder_get_handler($handler)) {
  246. drupal_set_message(t('Could not find handler @handler', array('@handler' => $handler)), 'error');
  247. drupal_not_found();
  248. exit();
  249. }
  250. if (($format && $format != 'default') && !in_array($format, array_keys(geoPHP::getAdapterMap()))) {
  251. throw new Exception(t('Could not find output-format @format', array('@format' => $format)), 'error');
  252. exit();
  253. }
  254. if (!geocoder_service_check_perms($handler)) {
  255. drupal_access_denied();
  256. exit();
  257. }
  258. }