'bounds')); */ function geocoder($handler, $data, $options = array(), $cache_type = 'DEPRECATED', $cache_reset = FALSE) { ctools_include('plugins'); $processor = ctools_get_plugins('geocoder', 'geocoder_handler', $handler); if (!$processor) { return NULL; } // Attempt to retrieve from persistent cache. $geometry = $cache_reset ? NULL : geocoder_cache_get($handler, $data, $options); // No cache record, so fetch live. if ($geometry === NULL) { try { // Load the file. geocoder_get_handler($handler); $geometry = call_user_func($processor['callback'], $data, $options); } catch (Exception $e) { watchdog_exception('geocoder', $e); return NULL; } // Always save result into persistent cache. geocoder_cache_set($geometry, $handler, $data, $options); } return $geometry; } /** * Implements hook_menu(). */ function geocoder_menu() { // Admin settings for the site. $items['admin/config/content/geocoder'] = array( 'title' => 'Geocoder settings', 'description' => 'Configuration for API keys.', 'page callback' => 'drupal_get_form', 'page arguments' => array('geocoder_admin_settings'), 'file' => 'geocoder.admin.inc', 'access arguments' => array('administer site configuration'), 'type' => MENU_NORMAL_ITEM, // optional ); $items['geocoder/service/%'] = array( 'title' => 'AJAX / AJAJ geocoding service', 'description' => 'Provides basic callback for geocoding using JavaScript', 'page callback' => 'geocoder_service_callback', 'page arguments' => array(2), 'type' => MENU_CALLBACK, 'access arguments' => array(arg(2)), 'access callback' => 'geocoder_service_check_perms', ); return $items; } /** * Geocoder Handler Information * * Return a list of all handlers that might geocode something for you. * Optionally you may pass a field-type and get back a list of * handlers that are compatible with that field. */ function geocoder_handler_info($field_type = NULL) { ctools_include('plugins'); static $handlers; if (!$handlers) { $handlers = ctools_get_plugins('geocoder', 'geocoder_handler'); } if ($field_type) { $field_handlers = $handlers; foreach ($field_handlers as $i => $handler) { if (!isset($handler['field_types']) || !in_array($field_type, $handler['field_types'])) { unset($field_handlers[$i]); } } return $field_handlers; } return $handlers; } /** * Fetch geocoder handler * * Given a name, fetch the full handler definition */ function geocoder_get_handler($handler_name) { $handlers = geocoder_handler_info(); if (isset($handlers[$handler_name])) { require_once $handlers[$handler_name]['path'] . '/' . $handlers[$handler_name]['file']; return $handlers[$handler_name]; } else return FALSE; } /** * Get supported field types * * Get a list of supported field types along with the processors that support them */ function geocoder_supported_field_types() { $supported = array(); $processors = geocoder_handler_info(); foreach ($processors as $processor) { if (isset($processor['field_types'])) { foreach ($processor['field_types'] as $field_type) { $supported[$field_type][] = $processor['name']; } } } return $supported; } /** * Implementation of hook_ctools_plugin_api(). */ function geocoder_ctools_plugin_api() { return array('version' => 1); } /** * Implementation of hook_ctools_plugin_directory() to let the system know * we implement plugins. */ function geocoder_ctools_plugin_directory($module, $plugin) { return 'plugins/' . $plugin; } /** * Implements hook_ctools_plugin_type */ function geocoder_ctools_plugin_type() { return array( 'geocoder_handler' => array( 'cache' => TRUE, ), ); } // These functions have to do with providing AJAX / AHAH // service functionality so that users can make use of // geocoder interactively via JavaScript. /** * Implements hook_permission(). * * We define permissions for accessing geocoder over AJAX / services. * There is one global permission which gives access to everything, * and one permission per handler. The site-administrator can therefore * fine tune which handlers are accessible. Note that to use AJAX with * geocoder these permissions need to be set. */ function geocoder_permission() { $handler_info = geocoder_handler_info(); $perms = array( 'geocoder_service_all_handlers' => array( 'title' => t('Can use all Geocoder handlers through AJAX / service'), ), ); foreach ($handler_info as $name => $handler) { $perms['geocoder_service_handler_' . $name] = array( 'title' => t('Can geocode using @handler through AJAX / service', array('@handler' => $handler['title'])), ); } return $perms; } /** * Geocoder service check permissions * * Given a handler, check to see if the user has * permission to execute it via AJAX / services */ function geocoder_service_check_perms($handler) { return (user_access('geocoder_service_all_handlers') || user_access('geocoder_service_handler_' . $handler)); } /** * Page callback for AJAX / Geocoder service * * This service can be accessed at /geocoder/service/ * and takes the query-parameter "data". Optionally a "output" * parameter may also be passed. "output" corresponds to * geoPHP output formats. * * Some examples: * /geocoder/service/google?data=4925 Gair Ave, Terrace, BC * /geocoder/service/wkt?data=POINT(10 10) * /geocoder/service/yahoo?data=94112&output=wkt */ function geocoder_service_callback($handler) { if (!isset($_GET['data'])) { throw new Exception(t('No data parameter found')); exit(); } $format = isset($_GET['output']) ? $_GET['output'] : 'json'; geophp_load(); geocoder_service_check_request($handler, $format); $geom = geocoder($handler, $_GET['data']); header('Content-Type: ' . geocoder_service_get_content_type($format)); print $geom->out($format); exit(); } /** * Get Content-Type for an output format * * Given an output format, this helper function passes * a compatible HTTP content-type to be placed in the * header. */ function geocoder_service_get_content_type($format) { $types = array( 'json' => 'application/json', 'kml' => 'application/xml', 'georss' => 'application/xml', 'gpx' => 'application/xml', 'wkt' => 'text/plain', 'wkb' => 'text/plain', 'google_geocode' => 'text/plain', ); return $types[$format]; } /** * Geocoder Service Check Request * * Check to make sure the request to the service is valid. This * checks to make sure the handler and the format exists, and * also checks permission */ function geocoder_service_check_request($handler, $format, $check_ac = TRUE) { if (!geocoder_get_handler($handler)) { drupal_set_message(t('Could not find handler @handler', array('@handler' => $handler)), 'error'); drupal_not_found(); exit(); } if (($format && $format != 'default') && !in_array($format, array_keys(geoPHP::getAdapterMap()))) { throw new Exception(t('Could not find output-format @format', array('@format' => $format)), 'error'); exit(); } if (!geocoder_service_check_perms($handler)) { drupal_access_denied(); exit(); } } /** * Create a unified cache id from relevant cache data. */ function _geocoder_cache_cid($data) { ksort($data); return sha1(serialize($data)); } /** * Retrieve a cached geocoded location. * * @param string $handler * The handler used to geocode this data. * @param mixed $data * The data used to fetch live geo data. * @param array $options * Handler-specific options that have effect on the result. * * @return Geometry * A Geometry object, FALSE (no result), or NULL (no cache). */ function geocoder_cache_get($handler, $data, $options) { $data = compact('handler', 'data', 'options'); $cid = _geocoder_cache_cid($data); geophp_load(); if ($cache = cache_get($cid, 'cache_geocoder')) { return $cache->data['geometry']; } } /** * Cache a geocoded result. * * @param mixed $geometry * A Geometry object, or FALSE (no result). * @param string $handler * The handler used to geocode this data. * @param mixed $data * The data used to fetch live geo data. * @param array $options * Handler-specific options that have effect on the result. */ function geocoder_cache_set($geometry, $handler, $data, $options) { // Don't cache no-results, to live geocode the same data again next time. if (!$geometry && !variable_get('geocoder_cache_empty_results', TRUE)) { return; } // Construct the cache id from result-relevant parameters. $data = compact('handler', 'data', 'options'); $cid = _geocoder_cache_cid($data); // Cache result-relevant parameters together with the actual result, so cache records can be traced. $data['geometry'] = $geometry ? $geometry : FALSE; cache_set($cid, $data, 'cache_geocoder', variable_get('geocoder_cache_ttl', CACHE_PERMANENT)); }