CRM-19784: Encapsulated interactions with geocoding providers. Adopts an
authorFrank J. Gómez <frank@ginkgostreet.com>
Fri, 2 Feb 2018 13:53:10 +0000 (08:53 -0500)
committerFrank J. Gómez <frank@ginkgostreet.com>
Fri, 2 Feb 2018 23:17:27 +0000 (18:17 -0500)
approach like the factory pattern PHP developers will find familiar, with
plenty of deprecation notices re the changing approach. A specific goal
was to avoid fatal errors in which a geocoder that no longer exists is called.
This applies specifically to the Yahoo class but also generally, e.g., if an
extension that provides a geocoder goes missing due to deletion, changed paths,
etc.

CRM/Core/BAO/Address.php
CRM/Utils/GeocodeProvider.php [new file with mode: 0644]

index a3ca4343e130849098fc48ad5de155427c1c09f2..801d8a041e0751ea636b83364d109c7f49e16de2 100644 (file)
@@ -1340,4 +1340,24 @@ SELECT is_primary,
     return CRM_Core_PseudoConstant::get(__CLASS__, $fieldName, $params, $context);
   }
 
+  /**
+   * Add data from the configured geocoding provider.
+   *
+   * Generally this means latitude & longitude data.
+   *
+   * @param array $params
+   * @return bool
+   *   TRUE if params could be passed to a provider, else FALSE.
+   */
+  public static function addGeocoderData(&$params) {
+    try {
+      $provider = CRM_Utils_GeocodeProvider::getConfiguredProvider();
+    }
+    catch (CRM_Core_Exception $e) {
+      return FALSE;
+    }
+    $provider::format($params);
+    return TRUE;
+  }
+
 }
diff --git a/CRM/Utils/GeocodeProvider.php b/CRM/Utils/GeocodeProvider.php
new file mode 100644 (file)
index 0000000..172814a
--- /dev/null
@@ -0,0 +1,81 @@
+<?php
+
+/*
+  +--------------------------------------------------------------------+
+  | CiviCRM version 4.7                                                |
+  +--------------------------------------------------------------------+
+  | Copyright CiviCRM LLC (c) 2004-2017                                |
+  +--------------------------------------------------------------------+
+  | This file is a part of CiviCRM.                                    |
+  |                                                                    |
+  | CiviCRM is free software; you can copy, modify, and distribute it  |
+  | under the terms of the GNU Affero General Public License           |
+  | Version 3, 19 November 2007 and the CiviCRM Licensing Exception.   |
+  |                                                                    |
+  | CiviCRM is distributed in the hope that it will be useful, but     |
+  | WITHOUT ANY WARRANTY; without even the implied warranty of         |
+  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.               |
+  | See the GNU Affero General Public License for more details.        |
+  |                                                                    |
+  | You should have received a copy of the GNU Affero General Public   |
+  | License and the CiviCRM Licensing Exception along                  |
+  | with this program; if not, contact CiviCRM LLC                     |
+  | at info[AT]civicrm[DOT]org. If you have questions about the        |
+  | GNU Affero General Public License or the licensing of CiviCRM,     |
+  | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
+  +--------------------------------------------------------------------+
+ */
+
+/**
+ *
+ * @package CRM
+ * @copyright CiviCRM LLC (c) 2004-2017
+ */
+class CRM_Utils_GeocodeProvider {
+
+  /**
+   * Instantiate a geocode object of the system-configured type.
+   *
+   * @return CRM_Utils_Geocode
+   * @throws CRM_Core_Exception
+   */
+  public static function getConfiguredProvider() {
+    $geoCodeClassName = self::getUsableClassName();
+    if ($geoCodeClassName === FALSE) {
+      throw new CRM_Core_Exception('No valid geocoding provider enabled');
+    }
+    return new $geoCodeClassName();
+  }
+
+  /**
+   * Get the name of the geocoding class if enabled.
+   *
+   * This retrieves the geocoding class, checking it can be accessed.
+   * Checks are done to mitigate the possibility it has been configured
+   * and then the file has been removed.
+   *
+   * @return string|bool
+   *   Class name if usable, else false.
+   */
+  public static function getUsableClassName() {
+    $provider = Civi::settings()->get('geoProvider');
+    if (!class_exists($provider)) {
+      if (strlen($provider)) {
+        Civi::log()->error('Configured geocoder has been removed from the system', ['geocode_class' => $provider]);
+      }
+      return FALSE;
+    }
+
+    // Ideally geocoding providers would be required to implement an interface
+    // or extend a base class. While we identify and implement a geocoding
+    // abstraction library (rather than continue to roll our own), we settle for
+    // this check.
+    if (!method_exists($provider, 'format')) {
+      Civi::log()->error('Configured geocoder is invalid, must provide a format method', ['geocode_class' => $provider]);
+      return FALSE;
+    }
+
+    return $provider;
+  }
+
+}