geocoder.widget.inc 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729
  1. <?php
  2. /**
  3. * @file
  4. * geocoder.widget.inc
  5. */
  6. /**
  7. * Implements hook_field_widget_info().
  8. */
  9. function geocoder_field_widget_info() {
  10. return array(
  11. 'geocoder' => array(
  12. 'label' => t('Geocode from another field'),
  13. 'field types' => array(
  14. 'geofield',
  15. 'geolocation_latlng',
  16. 'location',
  17. 'postgis',
  18. ),
  19. 'settings' => array(
  20. 'geocoder_field' => NULL,
  21. 'geocoder_handler' => NULL,
  22. 'handler_settings' => array(),
  23. 'delta_handling' => 'default',
  24. ),
  25. 'behaviors' => array(
  26. 'multiple values' => FIELD_BEHAVIOR_CUSTOM,
  27. 'default value' => FIELD_BEHAVIOR_NONE,
  28. ),
  29. ),
  30. );
  31. }
  32. /**
  33. * Implements field_widget_settings_form().
  34. */
  35. function geocoder_field_widget_settings_form($this_field, $instance) {
  36. $settings = $instance['widget']['settings'];
  37. $entity_fields = field_info_instances($instance['entity_type'], $instance['bundle']);
  38. $all_fields = field_info_fields();
  39. $supported_field_types = geocoder_supported_field_types();
  40. $processors = geocoder_handler_info();
  41. $handlers_by_type = array();
  42. $field_types = array();
  43. $valid_fields = array();
  44. $available_handlers = array();
  45. // Add in the title/name.
  46. // @@TODO Do this programatically by getting entity_info
  47. switch ($instance['entity_type']) {
  48. case 'node':
  49. $all_fields['title'] = array(
  50. 'field_name' => 'title',
  51. 'type' => 'text',
  52. );
  53. $entity_fields['title']['label'] = t('Title');
  54. break;
  55. case 'taxonomy_term':
  56. $all_fields['name'] = array(
  57. 'field_name' => 'name',
  58. 'type' => 'text',
  59. );
  60. $entity_fields['name']['label'] = t('Name');
  61. break;
  62. case 'country':
  63. $all_fields['name'] = array(
  64. 'field_name' => 'name',
  65. 'type' => 'text',
  66. );
  67. $entity_fields['name']['label'] = t('Name');
  68. break;
  69. }
  70. // Get a list of all valid fields that we both support and are part of this
  71. // entity.
  72. foreach ($all_fields as $field) {
  73. if (array_key_exists($field['field_name'], $entity_fields)) {
  74. if (in_array($field['type'], array_keys($supported_field_types), TRUE) && ($field['field_name'] !== $this_field['field_name'])) {
  75. $valid_fields[$field['field_name']] = $entity_fields[$field['field_name']]['label'];
  76. foreach ($supported_field_types[$field['type']] as $handler) {
  77. $available_handlers[$handler] = $processors[$handler]['title'];
  78. $handlers_by_type[$field['type']][] = $handler;
  79. $field_types[$field['field_name']] = $field['type'];
  80. }
  81. }
  82. }
  83. }
  84. // Extend with virtual fields.
  85. $info = entity_get_property_info($instance['entity_type']);
  86. foreach ($info as $property_name => $property) {
  87. if (isset($property['type']) && in_array($property['type'], array('location', 'text'), TRUE)) {
  88. if (!isset($valid_fields[$property_name])) {
  89. $valid_fields[$property_name] = $property['label'];
  90. }
  91. }
  92. }
  93. natcasesort($valid_fields);
  94. $form['geocoder_field'] = array(
  95. '#type' => 'select',
  96. '#title' => t('Geocode from field'),
  97. '#default_value' => isset($settings['geocoder_field']) ? $settings['geocoder_field'] : '',
  98. '#options' => $valid_fields,
  99. '#description' => t('Select which field you would like to geocode from.'),
  100. '#required' => TRUE,
  101. );
  102. $form['geocoder_handler'] = array(
  103. '#type' => 'select',
  104. '#title' => t('Geocoder'),
  105. '#prefix' => '<div id="geocoder-handler-div">',
  106. '#suffix' => '</div>',
  107. '#default_value' => isset($settings['geocoder_handler']) ? $settings['geocoder_handler'] : '',
  108. '#options' => $available_handlers,
  109. '#description' => t('Select which type of geocoding handler you would like to use'),
  110. '#required' => TRUE,
  111. );
  112. $form['handler_settings'] = array(
  113. '#tree' => TRUE,
  114. );
  115. // Add the handler settings forms.
  116. foreach ($processors as $handler_id => $handler) {
  117. if (isset($handler['settings_callback']) || isset($handler['terms_of_service'])) {
  118. $default_values = isset($settings['handler_settings'][$handler_id]) ? $settings['handler_settings'][$handler_id] : array();
  119. $form['handler_settings'][$handler_id] = array();
  120. $form['handler_settings'][$handler_id]['#type'] = 'fieldset';
  121. $form['handler_settings'][$handler_id]['#attributes'] = array('class' => array('geocoder-handler-setting', 'geocoder-handler-setting-' . $handler_id));
  122. $form['handler_settings'][$handler_id]['#title'] = $handler['title'] . ' Settings';
  123. $form['handler_settings'][$handler_id]['#states'] = array(
  124. 'visible' => array(
  125. ':input[id="edit-instance-widget-settings-geocoder-handler"]' => array('value' => $handler_id),
  126. ),
  127. );
  128. if (isset($handler['terms_of_service'])) {
  129. $form['handler_settings'][$handler_id]['tos'] = array(
  130. '#type' => 'item',
  131. '#markup' => t('This handler has terms of service. Click the following link to learn more.') . ' ' . l($handler['terms_of_service'], $handler['terms_of_service']),
  132. );
  133. }
  134. if (isset($handler['settings_callback'])) {
  135. // Load the file.
  136. geocoder_get_handler($handler_id);
  137. $settings_callback = $handler['settings_callback'];
  138. $form['handler_settings'][$handler_id] = array_merge($form['handler_settings'][$handler_id], $settings_callback($default_values));
  139. }
  140. }
  141. }
  142. $form['delta_handling'] = array(
  143. '#type' => 'select',
  144. '#title' => t('Multi-value input handling'),
  145. '#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>'),
  146. '#default_value' => isset($settings['delta_handling']) ? $settings['delta_handling'] : 'default',
  147. '#options' => array(
  148. 'default' => 'Match Multiples (default)',
  149. 'm_to_s' => 'Multiple to Single',
  150. 's_to_m' => 'Single to Multiple',
  151. 'c_to_s' => 'Concatenate to Single',
  152. 'c_to_m' => 'Concatenate to Multiple',
  153. ),
  154. '#required' => TRUE,
  155. );
  156. $form['latlng_override'] = array(
  157. '#type' => 'checkbox',
  158. '#title' => t('Allow manual lat/long override'),
  159. '#default_value' => isset($settings['latlng_override']) ? $settings['latlng_override'] : FALSE,
  160. '#description' => t('Allow the user to override geolocation lat/long values manually. Useful when geocoding is inaccurate.'),
  161. );
  162. // Add javascript to sync allowed values. Note that we are not using AJAX
  163. // because we do not have access to the raw form_state here.
  164. drupal_add_js(array('geocoder_widget_settings' => array('handlers' => $handlers_by_type, 'types' => $field_types)), 'setting');
  165. drupal_add_js(drupal_get_path('module', 'geocoder') . '/geocoder.admin.js', 'file');
  166. return $form;
  167. }
  168. /**
  169. * Implements hook_field_widget_form().
  170. */
  171. function geocoder_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $base) {
  172. $widget = $instance['widget'];
  173. $settings = $widget['settings'];
  174. if ($widget['type'] === 'geocoder' && !empty($settings['latlng_override'])) {
  175. $instance['widget']['type'] = 'geofield_latlon';
  176. $element = geofield_field_widget_form($form, $form_state, $field, $instance, $langcode, $items, $delta, $base);
  177. // At present, the only way we know if the user has overridden the lat/long
  178. // values is to perform a geocode and compare with the existing values.
  179. $geocoded_value = geocoder_widget_get_field_value($instance['entity_type'], $instance, $form['#entity']);
  180. $override_default = FALSE;
  181. if ($geocoded_value &&
  182. (round($element['geom']['#default_value']['lat'], 3) !== round($geocoded_value[$element['#language']][$delta]['lat'], 3)
  183. || round($element['geom']['#default_value']['lon'], 3) !== round($geocoded_value[$element['#language']][$delta]['lon'], 3))
  184. ) {
  185. $override_default = TRUE;
  186. }
  187. $element['geocoder_overridden'] = array(
  188. '#type' => 'checkbox',
  189. '#title' => t('Override lat/long values'),
  190. '#weight' => -10,
  191. '#default_value' => $override_default,
  192. '#description' => t('If address geocoding is inaccurate, check this box to override the lat/long values manually.'),
  193. );
  194. // Add element process to states to lat/long.
  195. $element['#process'][] = 'geocoder_process_override';
  196. $element['#element_validate'][] = 'geocoder_element_validate';
  197. return array($delta => $element);
  198. }
  199. }
  200. /**
  201. * Geocoder element validate function.
  202. */
  203. function geocoder_element_validate($element, &$form_state) {
  204. if (!empty($element['geocoder_overridden']) && !empty($form_state['values'][$element['#field_name']][$element['#language']][$element['#delta']]['geocoder_overridden'])) {
  205. // Set the form state value on entity to persist the flag.
  206. $form_state['values']['geocoder_overridden'][$element['#field_name']][$element['#language']][$element['#delta']] = TRUE;
  207. }
  208. else {
  209. $form_state['values']['geocoder_overridden'][$element['#field_name']][$element['#language']][$element['#delta']] = FALSE;
  210. }
  211. }
  212. /**
  213. * Geocoder element process function.
  214. */
  215. function geocoder_process_override($element) {
  216. $parents = $element['#parents'];
  217. $first_parent = array_shift($parents);
  218. $name = $first_parent . '[' . implode('][', $parents) . '][geocoder_overridden]';
  219. // Only display lat/long inputs if override is checked.
  220. $element['geom']['#states'] = array(
  221. 'visible' => array(
  222. ':input[name="' . $name . '"]' => array('checked' => TRUE),
  223. ),
  224. );
  225. return $element;
  226. }
  227. /**
  228. * Implements hook_field_attach_load().
  229. */
  230. function geocoder_field_attach_load($entity_type, $entities, $age, $options) {
  231. // Loop over all the entities looking for entities with geocoder field.
  232. foreach ($entities as &$entity) {
  233. list(, , $bundle) = entity_extract_ids($entity_type, $entity);
  234. // Examine every geocoder field instance attached to this entity's bundle.
  235. foreach (field_info_instances($entity_type, $bundle) as $field_name => $instance) {
  236. if ($instance['widget']['type'] === 'geocoder'
  237. && !empty($instance['widget']['settings']['latlng_override'])
  238. && ($geocoded_value = geocoder_widget_get_field_value($entity_type, $instance, $entity))) {
  239. foreach ($entity->{$field_name} as $langcode => $items) {
  240. foreach ($items as $delta => $item) {
  241. if ((round($item['lat'], 3) !== round($geocoded_value[$langcode][$delta]['lat'], 3)
  242. || round($item['lon'], 3) !== round($geocoded_value[$langcode][$delta]['lon'], 3))
  243. ) {
  244. $entity->geocoder_overridden[$field_name][$langcode][$delta] = TRUE;
  245. }
  246. }
  247. }
  248. }
  249. }
  250. }
  251. }
  252. /**
  253. * Implements hook_field_attach_presave().
  254. *
  255. * Geocoding for the geocoder widget is done here to ensure that only validated
  256. * and fully processed fields values are accessed.
  257. */
  258. function geocoder_field_attach_presave($entity_type, $entity) {
  259. list(,, $bundle) = entity_extract_ids($entity_type, $entity);
  260. // Loop over any geofield using our geocode widget.
  261. foreach (field_info_instances($entity_type, $bundle) as $field_name => $instance) {
  262. if ($instance['widget']['type'] === 'geocoder') {
  263. if ($geocoded_value = geocoder_widget_get_field_value($entity_type, $instance, $entity)) {
  264. if (!empty($entity->{$field_name})) {
  265. foreach ($entity->{$field_name} as $langcode => $items) {
  266. if (empty($items)) {
  267. $entity->{$field_name} = $geocoded_value;
  268. break;
  269. }
  270. foreach ($items as $delta => $item) {
  271. // Check the entity value.
  272. 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]))) {
  273. $entity->{$field_name}[$langcode][$delta] = $geocoded_value[$langcode][$delta];
  274. }
  275. }
  276. }
  277. }
  278. else {
  279. $entity->{$field_name} = $geocoded_value;
  280. }
  281. }
  282. else {
  283. $entity->{$field_name} = $geocoded_value;
  284. }
  285. }
  286. }
  287. }
  288. /**
  289. * Find a field instance's or entity property's relevant meta data.
  290. */
  291. function geocoder_widget_get_field_info($entity_type, $field_instance, $entity) {
  292. $entity_info = entity_get_info($entity_type);
  293. $field_name = is_array($field_instance['widget']['settings']['geocoder_field']) ? reset($field_instance['widget']['settings']['geocoder_field']) : $field_instance['widget']['settings']['geocoder_field'];
  294. // Determine the source type, if it's a entity-key, we mock it as a "text"
  295. // field.
  296. if (in_array($field_name, $entity_info['entity keys'], TRUE) && $entity) {
  297. $field_info = array('type' => 'text', 'entity_key' => TRUE);
  298. }
  299. else {
  300. $field_info = field_info_field($field_name);
  301. if (!$field_info) {
  302. $info = entity_get_all_property_info($entity_type);
  303. $field_info = $info[$field_name];
  304. }
  305. $field_info['entity_key'] = FALSE;
  306. }
  307. return $field_info;
  308. }
  309. /**
  310. * Return the value for the given proxy-field for the given entity.
  311. */
  312. function geocoder_widget_get_entity_field_value($entity_type, $field_instance, $entity) {
  313. $field_name = is_array($field_instance['widget']['settings']['geocoder_field']) ? reset($field_instance['widget']['settings']['geocoder_field']) : $field_instance['widget']['settings']['geocoder_field'];
  314. $field_info = geocoder_widget_get_field_info($entity_type, $field_instance, $entity);
  315. // Get the source values.
  316. if ($field_info['entity_key'] && $entity) {
  317. $source_field_values = array(array('value' => $entity->$field_name));
  318. }
  319. elseif ($entity) {
  320. $wrapper = entity_metadata_wrapper($entity_type, $entity);
  321. if (!empty($wrapper->value()->$field_name)) {
  322. $field_wrapper = $wrapper->value()->$field_name;
  323. }
  324. else {
  325. return FALSE;
  326. }
  327. $langcode = field_language($entity_type, $entity, $field_name);
  328. $value = $field_wrapper[$langcode];
  329. $values = array_filter(is_array($value) && isset($value[0]) ? $value : array($value));
  330. $source_field_values = array_map(function ($value) {
  331. if (is_array($value)) {
  332. // Clean up array from Addressfield, for diff.
  333. unset($value['element_key']);
  334. // Clean up array from Location, for diff.
  335. unset($value['location_settings'], $value['country_name'], $value['latitude'], $value['longitude'], $value['lid']);
  336. return array_filter($value);
  337. }
  338. return array('value' => $value);
  339. }, $values);
  340. }
  341. else {
  342. // We can't find the source values.
  343. return FALSE;
  344. }
  345. return $source_field_values;
  346. }
  347. /**
  348. * Get a field's value based on geocoded data.
  349. *
  350. * @param string $entity_type
  351. * Type of entity.
  352. * @param array $field_instance
  353. * Field instance definition array.
  354. * @param mixed $entity
  355. * Optionally, the entity. Pass either the entity or $source_field_values.
  356. * @param array $source_field_values
  357. * Array of deltas / source field values. Pass either this or $entity.
  358. *
  359. * @return bool|array
  360. * Three possibilities could be returned by this function:
  361. * - FALSE: do nothing.
  362. * - An empty array: use it to unset the existing field value.
  363. * - A populated array: assign a new field value.
  364. */
  365. function geocoder_widget_get_field_value($entity_type, array $field_instance, $entity = NULL, array $source_field_values = NULL) {
  366. if (!$source_field_values && !$entity) {
  367. trigger_error('geocoder_widget_get_field_value: You must pass either $source_field_values OR $entity', E_USER_ERROR);
  368. return FALSE;
  369. }
  370. // Required settings.
  371. if (isset($field_instance['widget']['settings']['geocoder_handler']) && isset($field_instance['widget']['settings']['geocoder_field'])) {
  372. $handler = geocoder_get_handler($field_instance['widget']['settings']['geocoder_handler']);
  373. $field_name = is_array($field_instance['widget']['settings']['geocoder_field']) ? reset($field_instance['widget']['settings']['geocoder_field']) : $field_instance['widget']['settings']['geocoder_field'];
  374. $target_info = field_info_field($field_instance['field_name']);
  375. $field_info = geocoder_widget_get_field_info($entity_type, $field_instance, $entity);
  376. // Get the source values.
  377. if (!$source_field_values) {
  378. $source_field_values = geocoder_widget_get_entity_field_value($entity_type, $field_instance, $entity);
  379. }
  380. // If no valid source values were passed.
  381. if (empty($source_field_values)) {
  382. return array();
  383. }
  384. // Get the handler-specific-settings.
  385. if (isset($field_instance['widget']['settings']['handler_settings'][$handler['name']])) {
  386. $handler_settings = $field_instance['widget']['settings']['handler_settings'][$handler['name']];
  387. }
  388. else {
  389. $handler_settings = array();
  390. }
  391. // Determine how we deal with deltas (multi-value fields)
  392. if (empty($field_instance['widget']['settings']['delta_handling'])) {
  393. $delta_handling = 'default';
  394. }
  395. else {
  396. $delta_handling = $field_instance['widget']['settings']['delta_handling'];
  397. }
  398. // Check to see if we should be concatenating.
  399. if ($delta_handling === 'c_to_s' || $delta_handling === 'c_to_m') {
  400. $source_field_values = geocoder_widget_get_field_concat($source_field_values);
  401. }
  402. // Allow other modules to alter values before we geocode them.
  403. drupal_alter('geocoder_geocode_values', $source_field_values, $field_info, $handler_settings, $field_instance);
  404. if (is_array($source_field_values) && count($source_field_values)) {
  405. // Geocode geometries.
  406. $geometries = array();
  407. foreach ($source_field_values as $delta => $item) {
  408. $geometry = NULL;
  409. if (!variable_get('geocoder_recode', 0)) {
  410. // Attempt to retrieve from persistent cache.
  411. $geometry = geocoder_cache_get($handler['name'], $item, $handler_settings);
  412. }
  413. // No cache record, so fetch live.
  414. if ($geometry === NULL || ($geometry === FALSE && !variable_get('geocoder_cache_empty_results'))) {
  415. // Geocode any value from our source field.
  416. try {
  417. $geometry = call_user_func($handler['field_callback'], $field_info, $item, $handler_settings);
  418. // Save result persistently.
  419. geocoder_cache_set($geometry, $handler['name'], $item, $handler_settings);
  420. }
  421. // Exception affects just this one field item.
  422. catch (Exception $e) {
  423. watchdog_exception('geocoder', $e, NULL, array(), WATCHDOG_ERROR, geocoder_widget_get_link($entity_type, $entity));
  424. continue;
  425. }
  426. }
  427. if ($geometry instanceof Geometry) {
  428. $geometries[] = $geometry;
  429. }
  430. elseif (variable_get('geocoder_log_empty_results', FALSE)) {
  431. watchdog('geocoder', 'No results for geocoding', NULL, WATCHDOG_NOTICE, geocoder_widget_get_link($entity_type, $entity));
  432. }
  433. }
  434. if (empty($geometries)) {
  435. // This field has no data, so set the field to an empty array in
  436. // order to delete its saved data.
  437. return array();
  438. }
  439. // Resolve multiple-values - get back values from our delta-resolver.
  440. $values = geocoder_widget_resolve_deltas($geometries, $delta_handling, $target_info);
  441. // Set the values - geofields do not support languages.
  442. return array(LANGUAGE_NONE => $values);
  443. }
  444. }
  445. }
  446. /**
  447. * Get field items and info.
  448. *
  449. * We always pass the full field-item array (with all columns) to the handler,
  450. * but there is some preprocessing that we need to do for the special case of
  451. * entity-labels and multi-field concatenation. For these two special cases we
  452. * "mock-up" a text-field and pass it back for geocoding.
  453. */
  454. function geocoder_widget_get_field_concat($items) {
  455. // Check if we should concatenate.
  456. $concat = '';
  457. foreach ($items as $item) {
  458. if (!empty($item['value'])) {
  459. $concat .= trim($item['value']) . ', ';
  460. }
  461. }
  462. $concat = trim($concat, ', ');
  463. $items = array(array('value' => $concat));
  464. return $items;
  465. }
  466. /**
  467. * Geocoder Widget - Resolve Deltas.
  468. *
  469. * Given a list of geometries, and user configuration on how to handle deltas,
  470. * we created a list of items to be inserted into the fields.
  471. */
  472. function geocoder_widget_resolve_deltas($geometries, $delta_handling, $target_info) {
  473. $values = array();
  474. if (empty($delta_handling)) {
  475. $delta_handling = 'default';
  476. }
  477. // Default delta handling: just pass one delta to the next.
  478. if ($delta_handling === 'default') {
  479. foreach ($geometries as $geometry) {
  480. $values[] = geocoder_widget_values_from_geometry($geometry, $target_info);
  481. }
  482. }
  483. // Single-to-multiple handling - if we can, explode out the component
  484. // geometries.
  485. if ($delta_handling === 's_to_m' || $delta_handling === 'c_to_m') {
  486. $type = $geometries[0]->geometryType();
  487. $geometry_types = array(
  488. 'MultiPoint',
  489. 'MultiLineString',
  490. 'MultiPolygon',
  491. 'GeometryCollection',
  492. );
  493. if (in_array($type, $geometry_types, TRUE)) {
  494. $components = $geometries[0]->getComponents();
  495. foreach ($components as $component) {
  496. $values[] = geocoder_widget_values_from_geometry($component, $target_info);
  497. }
  498. }
  499. else {
  500. $values[] = geocoder_widget_values_from_geometry($geometries[0], $target_info);
  501. }
  502. }
  503. // For multiple-to-single handling, run it though geometryReduce.
  504. if ($delta_handling === 'm_to_s' || $delta_handling === 'c_to_s') {
  505. $reduced_geom = geoPHP::geometryReduce($geometries);
  506. $values[] = geocoder_widget_values_from_geometry($reduced_geom, $target_info);
  507. }
  508. return $values;
  509. }
  510. /**
  511. * Geocoder Widget - Field values from geometry.
  512. *
  513. * Given a geometry and the field type, return back a values array for that
  514. * field. The passed back array represents a single delta.
  515. */
  516. function geocoder_widget_values_from_geometry($geometry, $target_info) {
  517. if ($target_info['type'] === 'geofield') {
  518. return geofield_get_values_from_geometry($geometry);
  519. }
  520. if ($target_info['type'] === 'geolocation_latlng') {
  521. $centroid = $geometry->centroid();
  522. $lat = $centroid->y();
  523. $lng = $centroid->x();
  524. return array(
  525. 'lat' => $lat,
  526. 'lng' => $lng,
  527. 'lat_sin' => sin(deg2rad($lat)),
  528. 'lat_cos' => cos(deg2rad($lat)),
  529. 'lng_rad' => deg2rad($lng),
  530. );
  531. }
  532. if ($target_info['type'] === 'location') {
  533. $centroid = $geometry->centroid();
  534. return array(
  535. 'latitude' => $centroid->y(),
  536. 'longitude' => $centroid->x(),
  537. 'source' => 2,
  538. );
  539. }
  540. if ($target_info['type'] === 'postgis') {
  541. $srid = $geometry->getSRID() ? $geometry->getSRID() : '4326';
  542. $type = $target_info['settings']['type'];
  543. $postgis_geometry = new PostgisGeometry($type, $srid);
  544. $postgis_geometry->fromText($geometry->asText());
  545. $postgis_geometry->transform($target_info['settings']['srid']);
  546. return array(
  547. 'geometry' => $postgis_geometry->getGeometry(),
  548. );
  549. }
  550. }
  551. /**
  552. * Geocoder Widget - Parse an address field.
  553. */
  554. function geocoder_widget_parse_addressfield($field_item) {
  555. $address = array();
  556. $address[] = !empty($field_item['organization']) ? $field_item['organization'] : NULL;
  557. $address[] = !empty($field_item['premise']) ? $field_item['premise'] : NULL;
  558. $address[] = !empty($field_item['sub_premise']) ? $field_item['sub_premise'] : NULL;
  559. $address[] = !empty($field_item['thoroughfare']) ? $field_item['thoroughfare'] : NULL;
  560. $address[] = !empty($field_item['locality']) ? $field_item['locality'] : NULL;
  561. $address[] = !empty($field_item['postal_code']) ? $field_item['postal_code'] : NULL;
  562. if (!empty($field_item['country']) && !empty($field_item['administrative_area'])) {
  563. module_load_include('inc', 'addressfield', 'addressfield.administrative_areas');
  564. $areas = addressfield_get_administrative_areas($field_item['country']);
  565. $address[] = $areas[$field_item['administrative_area']];
  566. }
  567. else {
  568. $address[] = !empty($field_item['administrative_area']) ? $field_item['administrative_area'] : NULL;
  569. }
  570. $address[] = !empty($field_item['sub_administrative_area']) ? $field_item['sub_administrative_area'] : NULL;
  571. if (!empty($field_item['country'])) {
  572. if (module_exists('countries')) {
  573. $country = country_load($field_item['country']);
  574. $field_item['country'] = $country->name;
  575. }
  576. else {
  577. // Convert country code to country name.
  578. include_once DRUPAL_ROOT . '/includes/locale.inc';
  579. $countries = country_get_list();
  580. if (array_key_exists($field_item['country'], $countries)) {
  581. $field_item['country'] = $countries[$field_item['country']];
  582. }
  583. }
  584. $address[] = $field_item['country'];
  585. }
  586. return implode(',', array_filter($address));
  587. }
  588. /**
  589. * Geocoder Widget - Parse a location field.
  590. */
  591. function geocoder_widget_parse_locationfield($field_item) {
  592. $address = '';
  593. if (!empty($field_item['street'])) {
  594. $address .= $field_item['street'] . ',';
  595. }
  596. if (!empty($field_item['additional'])) {
  597. $address .= $field_item['additional'] . ',';
  598. }
  599. if (!empty($field_item['city'])) {
  600. $address .= $field_item['city'] . ',';
  601. }
  602. if (!empty($field_item['postal_code'])) {
  603. $address .= $field_item['postal_code'] . ',';
  604. }
  605. if (!empty($field_item['province']) && function_exists('location_province_name')) {
  606. $province_fullname = location_province_name($field_item['country'], $field_item['province']);
  607. $address .= $province_fullname . ',';
  608. }
  609. if (!empty($field_item['country'])) {
  610. $address .= $field_item['country'] . ',';
  611. }
  612. $address = rtrim($address, ', ');
  613. return $address;
  614. }
  615. /**
  616. * Geocoder Widget - Parse a country field.
  617. */
  618. function geocoder_widget_parse_countryfield($field_item) {
  619. $address = '';
  620. $country = country_load($field_item['iso2']);
  621. if ($country) {
  622. $address = $country->name;
  623. }
  624. return $address;
  625. }
  626. /**
  627. * Geocoder Widget utility function to build a link for an entity.
  628. *
  629. * Ready for use in watchdog().
  630. */
  631. function geocoder_widget_get_link($entity_type, $entity) {
  632. if ($uri_info = entity_uri($entity_type, $entity)) {
  633. list($id, , $bundle) = entity_extract_ids($entity_type, $entity);
  634. $label = t('View offending @entity_type (@bundle #@id)', array(
  635. '@entity_type' => $entity_type,
  636. '@bundle' => $bundle,
  637. '@id' => $id,
  638. ));
  639. return l($label, $uri_info['path'], $uri_info);
  640. }
  641. return NULL;
  642. }