View source
<?php
function geocoder_field_widget_info() {
return array(
'geocoder' => array(
'label' => t('Geocode from another field'),
'field types' => array(
'geofield',
'geolocation_latlng',
'location',
'postgis',
),
'settings' => array(
'geocoder_field' => NULL,
'geocoder_handler' => NULL,
'handler_settings' => array(),
'delta_handling' => 'default',
),
'behaviors' => array(
'multiple values' => FIELD_BEHAVIOR_CUSTOM,
'default value' => FIELD_BEHAVIOR_NONE,
),
),
);
}
function geocoder_field_widget_settings_form($this_field, $instance) {
$settings = $instance['widget']['settings'];
$entity_fields = field_info_instances($instance['entity_type'], $instance['bundle']);
$all_fields = field_info_fields();
$supported_field_types = geocoder_supported_field_types();
$processors = geocoder_handler_info();
$handlers_by_type = array();
$field_types = array();
$valid_fields = array();
$available_handlers = array();
switch ($instance['entity_type']) {
case 'node':
$all_fields['title'] = array(
'field_name' => 'title',
'type' => 'text',
);
$entity_fields['title']['label'] = t('Title');
break;
case 'taxonomy_term':
$all_fields['name'] = array(
'field_name' => 'name',
'type' => 'text',
);
$entity_fields['name']['label'] = t('Name');
break;
case 'country':
$all_fields['name'] = array(
'field_name' => 'name',
'type' => 'text',
);
$entity_fields['name']['label'] = t('Name');
break;
}
foreach ($all_fields as $field) {
if (array_key_exists($field['field_name'], $entity_fields)) {
if (in_array($field['type'], array_keys($supported_field_types), TRUE) && $field['field_name'] !== $this_field['field_name']) {
$valid_fields[$field['field_name']] = $entity_fields[$field['field_name']]['label'];
foreach ($supported_field_types[$field['type']] as $handler) {
$available_handlers[$handler] = $processors[$handler]['title'];
$handlers_by_type[$field['type']][] = $handler;
$field_types[$field['field_name']] = $field['type'];
}
}
}
}
$info = entity_get_property_info($instance['entity_type']);
foreach ($info as $property_name => $property) {
if (isset($property['type']) && in_array($property['type'], array(
'location',
'text',
), TRUE)) {
if (!isset($valid_fields[$property_name])) {
$valid_fields[$property_name] = $property['label'];
}
}
}
natcasesort($valid_fields);
$form['geocoder_field'] = array(
'#type' => 'select',
'#title' => t('Geocode from field'),
'#default_value' => isset($settings['geocoder_field']) ? $settings['geocoder_field'] : '',
'#options' => $valid_fields,
'#description' => t('Select which field you would like to geocode from.'),
'#required' => TRUE,
);
$form['geocoder_handler'] = array(
'#type' => 'select',
'#title' => t('Geocoder'),
'#prefix' => '<div id="geocoder-handler-div">',
'#suffix' => '</div>',
'#default_value' => isset($settings['geocoder_handler']) ? $settings['geocoder_handler'] : '',
'#options' => $available_handlers,
'#description' => t('Select which type of geocoding handler you would like to use'),
'#required' => TRUE,
);
$form['handler_settings'] = array(
'#tree' => TRUE,
);
foreach ($processors as $handler_id => $handler) {
if (isset($handler['settings_callback']) || isset($handler['terms_of_service'])) {
$default_values = isset($settings['handler_settings'][$handler_id]) ? $settings['handler_settings'][$handler_id] : array();
$form['handler_settings'][$handler_id] = array();
$form['handler_settings'][$handler_id]['#type'] = 'fieldset';
$form['handler_settings'][$handler_id]['#attributes'] = array(
'class' => array(
'geocoder-handler-setting',
'geocoder-handler-setting-' . $handler_id,
),
);
$form['handler_settings'][$handler_id]['#title'] = $handler['title'] . ' Settings';
$form['handler_settings'][$handler_id]['#states'] = array(
'visible' => array(
':input[id="edit-instance-widget-settings-geocoder-handler"]' => array(
'value' => $handler_id,
),
),
);
if (isset($handler['terms_of_service'])) {
$form['handler_settings'][$handler_id]['tos'] = array(
'#type' => 'item',
'#markup' => t('This handler has terms of service. Click the following link to learn more.') . ' ' . l($handler['terms_of_service'], $handler['terms_of_service']),
);
}
if (isset($handler['settings_callback'])) {
geocoder_get_handler($handler_id);
$settings_callback = $handler['settings_callback'];
$form['handler_settings'][$handler_id] = array_merge($form['handler_settings'][$handler_id], $settings_callback($default_values));
}
}
}
$form['delta_handling'] = array(
'#type' => 'select',
'#title' => t('Multi-value input handling'),
'#description' => t('Should geometries from multiple inputs be: <ul><li>Matched with each input (e.g. One POINT for each address field)</li><li>Aggregated into a single MULTIPOINT geofield (e.g. One MULTIPOINT polygon from multiple address fields)</li><li>Broken up into multiple geometries (e.g. One MULTIPOINT to multiple POINTs.)</li></ul>'),
'#default_value' => isset($settings['delta_handling']) ? $settings['delta_handling'] : 'default',
'#options' => array(
'default' => 'Match Multiples (default)',
'm_to_s' => 'Multiple to Single',
's_to_m' => 'Single to Multiple',
'c_to_s' => 'Concatenate to Single',
'c_to_m' => 'Concatenate to Multiple',
),
'#required' => TRUE,
);
$form['latlng_override'] = array(
'#type' => 'checkbox',
'#title' => t('Allow manual lat/long override'),
'#default_value' => isset($settings['latlng_override']) ? $settings['latlng_override'] : FALSE,
'#description' => t('Allow the user to override geolocation lat/long values manually. Useful when geocoding is inaccurate.'),
);
drupal_add_js(array(
'geocoder_widget_settings' => array(
'handlers' => $handlers_by_type,
'types' => $field_types,
),
), 'setting');
drupal_add_js(drupal_get_path('module', 'geocoder') . '/geocoder.admin.js', 'file');
return $form;
}
function geocoder_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $base) {
$widget = $instance['widget'];
$settings = $widget['settings'];
if ($widget['type'] === 'geocoder' && !empty($settings['latlng_override'])) {
$instance['widget']['type'] = 'geofield_latlon';
$element = geofield_field_widget_form($form, $form_state, $field, $instance, $langcode, $items, $delta, $base);
$geocoded_value = geocoder_widget_get_field_value($instance['entity_type'], $instance, $form['#entity']);
$override_default = FALSE;
if ($geocoded_value && (round($element['geom']['#default_value']['lat'], 3) !== round($geocoded_value[$element['#language']][$delta]['lat'], 3) || round($element['geom']['#default_value']['lon'], 3) !== round($geocoded_value[$element['#language']][$delta]['lon'], 3))) {
$override_default = TRUE;
}
$element['geocoder_overridden'] = array(
'#type' => 'checkbox',
'#title' => t('Override lat/long values'),
'#weight' => -10,
'#default_value' => $override_default,
'#description' => t('If address geocoding is inaccurate, check this box to override the lat/long values manually.'),
);
$element['#process'][] = 'geocoder_process_override';
$element['#element_validate'][] = 'geocoder_element_validate';
return array(
$delta => $element,
);
}
}
function geocoder_element_validate($element, &$form_state) {
if (!empty($element['geocoder_overridden']) && !empty($form_state['values'][$element['#field_name']][$element['#language']][$element['#delta']]['geocoder_overridden'])) {
$form_state['values']['geocoder_overridden'][$element['#field_name']][$element['#language']][$element['#delta']] = TRUE;
}
else {
$form_state['values']['geocoder_overridden'][$element['#field_name']][$element['#language']][$element['#delta']] = FALSE;
}
}
function geocoder_process_override($element) {
$parents = $element['#parents'];
$first_parent = array_shift($parents);
$name = $first_parent . '[' . implode('][', $parents) . '][geocoder_overridden]';
$element['geom']['#states'] = array(
'visible' => array(
':input[name="' . $name . '"]' => array(
'checked' => TRUE,
),
),
);
return $element;
}
function geocoder_field_attach_load($entity_type, $entities, $age, $options) {
foreach ($entities as &$entity) {
list(, , $bundle) = entity_extract_ids($entity_type, $entity);
foreach (field_info_instances($entity_type, $bundle) as $field_name => $instance) {
if ($instance['widget']['type'] === 'geocoder' && !empty($instance['widget']['settings']['latlng_override']) && ($geocoded_value = geocoder_widget_get_field_value($entity_type, $instance, $entity))) {
foreach ($entity->{$field_name} as $langcode => $items) {
foreach ($items as $delta => $item) {
if (round($item['lat'], 3) !== round($geocoded_value[$langcode][$delta]['lat'], 3) || round($item['lon'], 3) !== round($geocoded_value[$langcode][$delta]['lon'], 3)) {
$entity->geocoder_overridden[$field_name][$langcode][$delta] = TRUE;
}
}
}
}
}
}
}
function geocoder_field_attach_presave($entity_type, $entity) {
list(, , $bundle) = entity_extract_ids($entity_type, $entity);
foreach (field_info_instances($entity_type, $bundle) as $field_name => $instance) {
if ($instance['widget']['type'] === 'geocoder') {
if ($geocoded_value = geocoder_widget_get_field_value($entity_type, $instance, $entity)) {
if (!empty($entity->{$field_name})) {
foreach ($entity->{$field_name} as $langcode => $items) {
if (empty($items)) {
$entity->{$field_name} = $geocoded_value;
break;
}
foreach ($items as $delta => $item) {
if (!(isset($entity->geocoder_overridden) && isset($entity->geocoder_overridden[$field_name]) && isset($entity->geocoder_overridden[$field_name][$langcode]) && !empty($entity->geocoder_overridden[$field_name][$langcode][$delta]))) {
$entity->{$field_name}[$langcode][$delta] = $geocoded_value[$langcode][$delta];
}
}
}
}
else {
$entity->{$field_name} = $geocoded_value;
}
}
else {
$entity->{$field_name} = $geocoded_value;
}
}
}
}
function geocoder_widget_get_field_info($entity_type, $field_instance, $entity) {
$entity_info = entity_get_info($entity_type);
$field_name = is_array($field_instance['widget']['settings']['geocoder_field']) ? reset($field_instance['widget']['settings']['geocoder_field']) : $field_instance['widget']['settings']['geocoder_field'];
if (in_array($field_name, $entity_info['entity keys'], TRUE) && $entity) {
$field_info = array(
'type' => 'text',
'entity_key' => TRUE,
);
}
else {
$field_info = field_info_field($field_name);
if (!$field_info) {
$info = entity_get_all_property_info($entity_type);
$field_info = $info[$field_name];
}
$field_info['entity_key'] = FALSE;
}
return $field_info;
}
function geocoder_widget_get_entity_field_value($entity_type, $field_instance, $entity) {
$field_name = is_array($field_instance['widget']['settings']['geocoder_field']) ? reset($field_instance['widget']['settings']['geocoder_field']) : $field_instance['widget']['settings']['geocoder_field'];
$field_info = geocoder_widget_get_field_info($entity_type, $field_instance, $entity);
if ($field_info['entity_key'] && $entity) {
$source_field_values = array(
array(
'value' => $entity->{$field_name},
),
);
}
elseif ($entity) {
$wrapper = entity_metadata_wrapper($entity_type, $entity);
if (!empty($wrapper
->value()->{$field_name})) {
$field_wrapper = $wrapper
->value()->{$field_name};
}
else {
return FALSE;
}
$langcode = field_language($entity_type, $entity, $field_name);
$value = $field_wrapper[$langcode];
$values = array_filter(is_array($value) && isset($value[0]) ? $value : array(
$value,
));
$source_field_values = array_map(function ($value) {
if (is_array($value)) {
unset($value['element_key']);
unset($value['location_settings'], $value['country_name'], $value['latitude'], $value['longitude'], $value['lid']);
return array_filter($value);
}
return array(
'value' => $value,
);
}, $values);
}
else {
return FALSE;
}
return $source_field_values;
}
function geocoder_widget_get_field_value($entity_type, array $field_instance, $entity = NULL, array $source_field_values = NULL) {
if (!$source_field_values && !$entity) {
trigger_error('geocoder_widget_get_field_value: You must pass either $source_field_values OR $entity', E_USER_ERROR);
return FALSE;
}
if (isset($field_instance['widget']['settings']['geocoder_handler']) && isset($field_instance['widget']['settings']['geocoder_field'])) {
$handler = geocoder_get_handler($field_instance['widget']['settings']['geocoder_handler']);
$field_name = is_array($field_instance['widget']['settings']['geocoder_field']) ? reset($field_instance['widget']['settings']['geocoder_field']) : $field_instance['widget']['settings']['geocoder_field'];
$target_info = field_info_field($field_instance['field_name']);
$field_info = geocoder_widget_get_field_info($entity_type, $field_instance, $entity);
if (!$source_field_values) {
$source_field_values = geocoder_widget_get_entity_field_value($entity_type, $field_instance, $entity);
}
if (empty($source_field_values)) {
return array();
}
if (isset($field_instance['widget']['settings']['handler_settings'][$handler['name']])) {
$handler_settings = $field_instance['widget']['settings']['handler_settings'][$handler['name']];
}
else {
$handler_settings = array();
}
if (empty($field_instance['widget']['settings']['delta_handling'])) {
$delta_handling = 'default';
}
else {
$delta_handling = $field_instance['widget']['settings']['delta_handling'];
}
if ($delta_handling === 'c_to_s' || $delta_handling === 'c_to_m') {
$source_field_values = geocoder_widget_get_field_concat($source_field_values);
}
drupal_alter('geocoder_geocode_values', $source_field_values, $field_info, $handler_settings, $field_instance);
if (is_array($source_field_values) && count($source_field_values)) {
$geometries = array();
foreach ($source_field_values as $delta => $item) {
$geometry = NULL;
if (!variable_get('geocoder_recode', 0)) {
$geometry = geocoder_cache_get($handler['name'], $item, $handler_settings);
}
if ($geometry === NULL || $geometry === FALSE && !variable_get('geocoder_cache_empty_results')) {
try {
$geometry = call_user_func($handler['field_callback'], $field_info, $item, $handler_settings);
geocoder_cache_set($geometry, $handler['name'], $item, $handler_settings);
} catch (Exception $e) {
watchdog_exception('geocoder', $e, NULL, array(), WATCHDOG_ERROR, geocoder_widget_get_link($entity_type, $entity));
continue;
}
}
if ($geometry instanceof Geometry) {
$geometries[] = $geometry;
}
elseif (variable_get('geocoder_log_empty_results', FALSE)) {
watchdog('geocoder', 'No results for geocoding', NULL, WATCHDOG_NOTICE, geocoder_widget_get_link($entity_type, $entity));
}
}
if (empty($geometries)) {
return array();
}
$values = geocoder_widget_resolve_deltas($geometries, $delta_handling, $target_info);
return array(
LANGUAGE_NONE => $values,
);
}
}
}
function geocoder_widget_get_field_concat($items) {
$concat = '';
foreach ($items as $item) {
if (!empty($item['value'])) {
$concat .= trim($item['value']) . ', ';
}
}
$concat = trim($concat, ', ');
$items = array(
array(
'value' => $concat,
),
);
return $items;
}
function geocoder_widget_resolve_deltas($geometries, $delta_handling = 'default', $target_info) {
$values = array();
if ($delta_handling === 'default') {
foreach ($geometries as $geometry) {
$values[] = geocoder_widget_values_from_geometry($geometry, $target_info);
}
}
if ($delta_handling === 's_to_m' || $delta_handling === 'c_to_m') {
$type = $geometries[0]
->geometryType();
$geometry_types = array(
'MultiPoint',
'MultiLineString',
'MultiPolygon',
'GeometryCollection',
);
if (in_array($type, $geometry_types, TRUE)) {
$components = $geometries[0]
->getComponents();
foreach ($components as $component) {
$values[] = geocoder_widget_values_from_geometry($component, $target_info);
}
}
else {
$values[] = geocoder_widget_values_from_geometry($geometries[0], $target_info);
}
}
if ($delta_handling === 'm_to_s' || $delta_handling === 'c_to_s') {
$reduced_geom = geoPHP::geometryReduce($geometries);
$values[] = geocoder_widget_values_from_geometry($reduced_geom, $target_info);
}
return $values;
}
function geocoder_widget_values_from_geometry($geometry, $target_info) {
if ($target_info['type'] === 'geofield') {
return geofield_get_values_from_geometry($geometry);
}
if ($target_info['type'] === 'geolocation_latlng') {
$centroid = $geometry
->centroid();
$lat = $centroid
->y();
$lng = $centroid
->x();
return array(
'lat' => $lat,
'lng' => $lng,
'lat_sin' => sin(deg2rad($lat)),
'lat_cos' => cos(deg2rad($lat)),
'lng_rad' => deg2rad($lng),
);
}
if ($target_info['type'] === 'location') {
$centroid = $geometry
->centroid();
return array(
'latitude' => $centroid
->y(),
'longitude' => $centroid
->x(),
'source' => 2,
);
}
if ($target_info['type'] === 'postgis') {
$srid = $geometry
->getSRID() ? $geometry
->getSRID() : '4326';
$type = $target_info['settings']['type'];
$postgis_geometry = new PostgisGeometry($type, $srid);
$postgis_geometry
->fromText($geometry
->asText());
$postgis_geometry
->transform($target_info['settings']['srid']);
return array(
'geometry' => $postgis_geometry
->getGeometry(),
);
}
}
function geocoder_widget_parse_addressfield($field_item) {
$address = array();
$address[] = !empty($field_item['organization']) ? $field_item['organization'] : NULL;
$address[] = !empty($field_item['premise']) ? $field_item['premise'] : NULL;
$address[] = !empty($field_item['sub_premise']) ? $field_item['sub_premise'] : NULL;
$address[] = !empty($field_item['thoroughfare']) ? $field_item['thoroughfare'] : NULL;
$address[] = !empty($field_item['locality']) ? $field_item['locality'] : NULL;
$address[] = !empty($field_item['postal_code']) ? $field_item['postal_code'] : NULL;
if (!empty($field_item['country']) && !empty($field_item['administrative_area'])) {
module_load_include('inc', 'addressfield', 'addressfield.administrative_areas');
$areas = addressfield_get_administrative_areas($field_item['country']);
$address[] = $areas[$field_item['administrative_area']];
}
else {
$address[] = !empty($field_item['administrative_area']) ? $field_item['administrative_area'] : NULL;
}
$address[] = !empty($field_item['sub_administrative_area']) ? $field_item['sub_administrative_area'] : NULL;
if (!empty($field_item['country'])) {
if (module_exists('countries')) {
$country = country_load($field_item['country']);
$field_item['country'] = $country->name;
}
else {
include_once DRUPAL_ROOT . '/includes/locale.inc';
$countries = country_get_list();
if (array_key_exists($field_item['country'], $countries)) {
$field_item['country'] = $countries[$field_item['country']];
}
}
$address[] = $field_item['country'];
}
return implode(',', array_filter($address));
}
function geocoder_widget_parse_locationfield($field_item) {
$address = '';
if (!empty($field_item['street'])) {
$address .= $field_item['street'] . ',';
}
if (!empty($field_item['additional'])) {
$address .= $field_item['additional'] . ',';
}
if (!empty($field_item['city'])) {
$address .= $field_item['city'] . ',';
}
if (!empty($field_item['postal_code'])) {
$address .= $field_item['postal_code'] . ',';
}
if (!empty($field_item['province']) && function_exists('location_province_name')) {
$province_fullname = location_province_name($field_item['country'], $field_item['province']);
$address .= $province_fullname . ',';
}
if (!empty($field_item['country'])) {
$address .= $field_item['country'] . ',';
}
$address = rtrim($address, ', ');
return $address;
}
function geocoder_widget_parse_countryfield($field_item) {
$address = '';
$country = country_load($field_item['iso2']);
if ($country) {
$address = $country->name;
}
return $address;
}
function geocoder_widget_get_link($entity_type, $entity) {
if ($uri_info = entity_uri($entity_type, $entity)) {
list($id, , $bundle) = entity_extract_ids($entity_type, $entity);
$label = t('View offending @entity_type (@bundle #@id)', array(
'@entity_type' => $entity_type,
'@bundle' => $bundle,
'@id' => $id,
));
return l($label, $uri_info['path'], $uri_info);
}
return NULL;
}