From 5a002bebbf0cf4d082604987a3a86d19a774fe88 Mon Sep 17 00:00:00 2001
From: Taran2L <Taran2L@473438.no-reply.drupal.org>
Date: Thu, 18 Feb 2016 13:59:14 +0200
Subject: [PATCH] Issue #2549333 by Taran2L: Add Migrate module support

---
 geolocation.devel_generate.inc       |  15 +---
 geolocation.info                     |   5 +-
 geolocation.migrate.inc              |  16 ++++
 geolocation.module                   |  27 +++++-
 migrate/destinations/geolocation.inc | 169 +++++++++++++++++++++++++++++++++++
 5 files changed, 215 insertions(+), 17 deletions(-)
 create mode 100644 geolocation.migrate.inc
 create mode 100644 migrate/destinations/geolocation.inc

diff --git a/geolocation.devel_generate.inc b/geolocation.devel_generate.inc
index 64b5ee7..caf0f93 100644
--- a/geolocation.devel_generate.inc
+++ b/geolocation.devel_generate.inc
@@ -21,19 +21,10 @@ function geolocation_devel_generate($object, $field, $instance, $bundle) {
  * Callback for hook_devel_generate().
  */
 function _geolocation_devel_generate($object, $field, $instance, $bundle) {
-  $lat = rand(-90, 90) - rand(0, 999999) / 1000000;
-  $lng = rand(-180, 180) - rand(0, 999999) / 1000000;
-  $lat_sin = sin(deg2rad($lat));;
-  $lat_cos = cos(deg2rad($lat));
-  $lng_rad = deg2rad($lng);
-
   $geolocation = array(
-    'lat' => $lat,
-    'lng' => $lng,
-    'lat_sin' => $lat_sin,
-    'lat_cos' => $lat_cos,
-    'lng_rad' => $lng_rad,
+    'lat' => rand(-90, 90) - rand(0, 999999) / 1000000,
+    'lng' => rand(-180, 180) - rand(0, 999999) / 1000000,
   );
 
-  return $geolocation;
+  return _geolocation_field_precalculate_values($geolocation);
 }
diff --git a/geolocation.info b/geolocation.info
index fcba671..4b48574 100644
--- a/geolocation.info
+++ b/geolocation.info
@@ -2,4 +2,7 @@
 name = Geolocation
 description = Provides a geolocation field.
 package = Geolocation
-core = 7.x
\ No newline at end of file
+core = 7.x
+
+; Migrate handlers
+files[] = migrate/destinations/geolocation.inc
diff --git a/geolocation.migrate.inc b/geolocation.migrate.inc
new file mode 100644
index 0000000..38bd4fc
--- /dev/null
+++ b/geolocation.migrate.inc
@@ -0,0 +1,16 @@
+<?php
+
+/**
+ * @file
+ * Integration with Migrate module.
+ */
+
+/**
+ * Implement hook_migrate_api().
+ */
+function geolocation_migrate_api() {
+  return array(
+    'api' => 2,
+    'field handlers' => array('MigrateGeolocationFieldHandler'),
+  );
+}
diff --git a/geolocation.module b/geolocation.module
index c956eae..1e4d524 100644
--- a/geolocation.module
+++ b/geolocation.module
@@ -144,10 +144,7 @@ function geolocation_field_validate($entity_type, $entity, $field, $instance, $l
 function geolocation_field_presave($entity_type, $entity, $field, $instance, $langcode, &$items) {
   foreach ($items as $delta => $item) {
     // Precalculate some goodness.
-    $item['lat_sin'] = sin(deg2rad($item['lat']));
-    $item['lat_cos'] = cos(deg2rad($item['lat']));
-    $item['lng_rad'] = deg2rad($item['lng']);
-    $items[$delta] = $item;
+    $items[$delta] = _geolocation_field_precalculate_values($item);
   }
 }
 
@@ -305,3 +302,25 @@ function geolocation_field_widget_error($element, $error, $form, &$form_state) {
       break;
   }
 }
+
+/**
+ * Helper function. Precalculates values for geolocation field item.
+ *
+ * @param array $item
+ *   Geolocation field item with the following keys:
+ *     - lat: (required) Latitude
+ *     - lng: (required) Longitude
+ *
+ * @return array
+ *   Geolocation field item with added precalculated values:
+ *     - lat_sin: Latitude sine
+ *     - lat_cos: Latitude cosine
+ *     - lng_rad: Radian longitude
+ */
+function _geolocation_field_precalculate_values(array $item) {
+  $item['lat_sin'] = sin(deg2rad($item['lat']));
+  $item['lat_cos'] = cos(deg2rad($item['lat']));
+  $item['lng_rad'] = deg2rad($item['lng']);
+
+  return $item;
+}
diff --git a/migrate/destinations/geolocation.inc b/migrate/destinations/geolocation.inc
new file mode 100644
index 0000000..4581499
--- /dev/null
+++ b/migrate/destinations/geolocation.inc
@@ -0,0 +1,169 @@
+<?php
+
+/**
+ * @file
+ * Contains geolocation field migration handler.
+ */
+
+/**
+ * Geolocation field migration handler class.
+ *
+ * Geolocation field requires both latitude and longitude values, so it doesn't
+ * make sense to use the primary value, i.e. map to field itself.
+ * In order to use it, please map values to the subfields (mapping to the field
+ * won't work).
+ *
+ * Subfields:
+ *   - 'lat': Geolocation field latitude value.
+ *   - 'lng': Geolocation field longitude value.
+ *   - 'language': Geolocation field value language.
+ *
+ * See more at https://www.drupal.org/node/2671068
+ */
+class MigrateGeolocationFieldHandler extends MigrateFieldHandler {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function __construct() {
+    $this->registerTypes(array('geolocation_latlng'));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  static public function arguments($lat = NULL, $lng = NULL, $language = NULL) {
+    $arguments = array();
+    if (!is_null($lat)) {
+      $arguments['lat'] = $lat;
+    }
+    if (!is_null($lng)) {
+      $arguments['lng'] = $lng;
+    }
+    if (!is_null($language)) {
+      $arguments['language'] = $language;
+    }
+    return $arguments;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function fields($type, $instance, $migration = NULL) {
+    return array(
+      'lat' => t('Subfield: Geolocation field latitude value'),
+      'lng' => t('Subfield: Geolocation field longitude value'),
+      'language' => t('Subfield:  Geolocation field value language'),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function prepare($entity, array $field_info, array $instance, array $values) {
+
+    $arguments = isset($values['arguments']) ? $values['arguments'] : array();
+    $arguments += array(
+      'lat' => array(),
+      'lng' => array(),
+    );
+
+    // When a single value is mapped to an argument, Migrate module doesn't wrap
+    // it in array.
+    foreach (array('lat', 'lng') as $subelement) {
+      if (!is_array($arguments[$subelement])) {
+        $arguments[$subelement] = array($arguments[$subelement]);
+      }
+    }
+
+    $return = array();
+    foreach ($arguments['lat'] as $delta => $value) {
+      $item = array(
+        'lat' => $arguments['lat'][$delta],
+        'lng' => isset($arguments['lng'][$delta]) ? $arguments['lng'][$delta] : NULL,
+      );
+
+      if ($this->validate($entity, $field_info, $instance, $item)) {
+        $language = $this->getGeolocationFieldLanguage($entity, $field_info, $arguments, $delta);
+        $return[$language][] = _geolocation_field_precalculate_values($item);
+      }
+    }
+
+    return !empty($return) ? $return : NULL;
+  }
+
+  /**
+   * Determines field language.
+   *
+   * @param object $entity
+   *   Entity being processed.
+   * @param array $field_info
+   *   Field info.
+   * @param array $arguments
+   *   Arguments passed to the field migration handler.
+   * @param int $delta
+   *   Field values delta.
+   *
+   * @return string
+   *   Language code.
+   *
+   * @see MigrateFieldHandler::getFieldLanguage()
+   */
+  public function getGeolocationFieldLanguage($entity, array $field_info, array $arguments, $delta = 0) {
+    static $language = NULL;
+
+    if (is_null($language)) {
+      $language = $this->getFieldLanguage($entity, $field_info, $arguments);
+    }
+
+    if (!is_array($language)) {
+      return $language;
+    }
+    else {
+      if (!empty($language[$delta])) {
+        return $language[$delta];
+      }
+      else {
+        return LANGUAGE_NONE;
+      }
+    }
+  }
+
+  /**
+   * Validates given geolocation field value item.
+   *
+   * @param object $entity
+   *   Entity being processed.
+   * @param array $field_info
+   *   Field info.
+   * @param array $instance
+   *   Field instance.
+   * @param array $item
+   *   Field values delta.
+   *
+   * @return bool
+   *   TRUE if given item contains valid geolocation field value, FALSE -
+   *   otherwise.
+   */
+  protected function validate($entity, array $field_info, array $instance, array $item) {
+    $item_is_valid = TRUE;
+
+    $migration = Migration::currentMigration();
+
+    if (((string) $item['lat'] === '') || ((string) $item['lng'] === '')) {
+      $migration->saveMessage(t('%name: both latitude and longitude values are required.', array('%name' => $instance['label'])), Migration::MESSAGE_ERROR);
+      $item_is_valid = FALSE;
+    }
+    if (!is_numeric($item['lat']) || !is_numeric($item['lng'])) {
+      $migration->saveMessage(t('%name: only numeric values are acceptable.', array('%name' => $instance['label'])), Migration::MESSAGE_ERROR);
+      $item_is_valid = FALSE;
+    }
+    if ($item['lat'] < -90 || $item['lat'] > 90 || $item['lng'] < -180 || $item['lng'] > 180) {
+      $migration->saveMessage(t('%name: invalid latitude or longitude has been provided.', array('%name' => $instance['label'])), Migration::MESSAGE_ERROR);
+      $item_is_valid = FALSE;
+    }
+
+    return $item_is_valid;
+  }
+
+}
-- 
2.6.2.windows.1

