From cb695d3e4baa5d332d3f7f4a1105bb2c090ec4ee Mon Sep 17 00:00:00 2001 From: Coleman Watts Date: Thu, 26 May 2022 08:15:13 -0400 Subject: [PATCH] APIv4 - Add Address::getCoordinates action --- CRM/Utils/Geocode/Google.php | 50 +++++++++++++++---- Civi/Api4/Action/Address/GetCoordinates.php | 43 ++++++++++++++++ Civi/Api4/Address.php | 9 ++++ .../Spec/Provider/AddressGetSpecProvider.php | 8 ++- 4 files changed, 98 insertions(+), 12 deletions(-) create mode 100644 Civi/Api4/Action/Address/GetCoordinates.php diff --git a/CRM/Utils/Geocode/Google.php b/CRM/Utils/Geocode/Google.php index ad670f6c94..0885a3d3ae 100644 --- a/CRM/Utils/Geocode/Google.php +++ b/CRM/Utils/Geocode/Google.php @@ -51,8 +51,6 @@ class CRM_Utils_Geocode_Google { return FALSE; } - $config = CRM_Core_Config::singleton(); - $add = ''; if (!empty($values['street_address'])) { @@ -99,6 +97,37 @@ class CRM_Utils_Geocode_Google { $add .= '+' . urlencode(str_replace('', '+', $values['country'])); } + $coord = self::makeRequest($add); + + $values['geo_code_1'] = $coord['geo_code_1'] ?? 'null'; + $values['geo_code_2'] = $coord['geo_code_2'] ?? 'null'; + + if (isset($coord['geo_code_error'])) { + $values['geo_code_error'] = $coord['geo_code_error']; + } + + return isset($coord['geo_code_1'], $coord['geo_code_2']); + } + + /** + * @param string $address + * Plain text address + * @return array + * @throws \GuzzleHttp\Exception\GuzzleException + */ + public static function getCoordinates($address) { + return self::makeRequest(urlencode($address)); + } + + /** + * @param string $add + * Url-encoded address + * @return array + * @throws \GuzzleHttp\Exception\GuzzleException + */ + private static function makeRequest($add) { + + $config = CRM_Core_Config::singleton(); if (!empty($config->geoAPIKey)) { $add .= '&key=' . urlencode($config->geoAPIKey); } @@ -115,7 +144,7 @@ class CRM_Utils_Geocode_Google { if ($xml === FALSE) { // account blocked maybe? CRM_Core_Error::debug_var('Geocoding failed. Message from Google:', $string); - return FALSE; + return ['geo_code_error' => $string]; } if (isset($xml->status)) { @@ -126,23 +155,22 @@ class CRM_Utils_Geocode_Google { ) { $ret = $xml->result->geometry->location->children(); if ($ret->lat && $ret->lng) { - $values['geo_code_1'] = (float) $ret->lat; - $values['geo_code_2'] = (float) $ret->lng; - return TRUE; + return [ + 'geo_code_1' => (float) $ret->lat, + 'geo_code_2' => (float) $ret->lng, + ]; } } elseif ($xml->status == 'ZERO_RESULTS') { // reset the geo code values if we did not get any good values - $values['geo_code_1'] = $values['geo_code_2'] = 'null'; - return FALSE; + return []; } else { CRM_Core_Error::debug_var("Geocoding failed. Message from Google: ({$xml->status})", (string ) $xml->error_message); - $values['geo_code_1'] = $values['geo_code_2'] = 'null'; - $values['geo_code_error'] = $xml->status; - return FALSE; + return ['geo_code_error' => $xml->status]; } } + return []; } } diff --git a/Civi/Api4/Action/Address/GetCoordinates.php b/Civi/Api4/Action/Address/GetCoordinates.php new file mode 100644 index 0000000000..86bcd16a49 --- /dev/null +++ b/Civi/Api4/Action/Address/GetCoordinates.php @@ -0,0 +1,43 @@ +address); + if (isset($coord['geo_code_1'], $coord['geo_code_2'])) { + $result[] = $coord; + } + elseif (!empty($coord['geo_code_error'])) { + throw new \API_Exception('Geocoding failed. ' . $coord['geo_code_error']); + } + } + +} diff --git a/Civi/Api4/Address.php b/Civi/Api4/Address.php index a4ec60aeb3..c9db2a8015 100644 --- a/Civi/Api4/Address.php +++ b/Civi/Api4/Address.php @@ -54,4 +54,13 @@ class Address extends Generic\DAOEntity { ->setCheckPermissions($checkPermissions); } + /** + * @param bool $checkPermissions + * @return Action\Address\GetCoordinates + */ + public static function getCoordinates($checkPermissions = TRUE) { + return (new Action\Address\GetCoordinates(__CLASS__, __FUNCTION__)) + ->setCheckPermissions($checkPermissions); + } + } diff --git a/Civi/Api4/Service/Spec/Provider/AddressGetSpecProvider.php b/Civi/Api4/Service/Spec/Provider/AddressGetSpecProvider.php index f3a5048caa..42765f3b15 100644 --- a/Civi/Api4/Service/Spec/Provider/AddressGetSpecProvider.php +++ b/Civi/Api4/Service/Spec/Provider/AddressGetSpecProvider.php @@ -12,6 +12,7 @@ namespace Civi\Api4\Service\Spec\Provider; +use Civi\Api4\Address; use Civi\Api4\Query\Api4SelectQuery; use Civi\Api4\Service\Spec\FieldSpec; use Civi\Api4\Service\Spec\RequestSpec; @@ -64,6 +65,12 @@ class AddressGetSpecProvider implements Generic\SpecProviderInterface { $distance = $distance * 1000.00; } + if (!isset($value['geo_code_1'], $value['geo_code_2'])) { + $value = Address::getCoordinates(FALSE) + ->setAddress($value['address']) + ->execute()->first(); + } + if ( isset($value['geo_code_1']) && is_numeric($value['geo_code_1']) && isset($value['geo_code_2']) && is_numeric($value['geo_code_2']) @@ -75,7 +82,6 @@ class AddressGetSpecProvider implements Generic\SpecProviderInterface { explode('.', $fieldAlias)[0] ); } - // Todo: If address string given without lat/long, convert it. return '(0)'; } -- 2.25.1