Merge pull request #17476 from civicrm/5.26
[civicrm-core.git] / CRM / Utils / Geocode / Google.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
5 | |
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
9 +--------------------------------------------------------------------+
10 */
11
12 /**
13 *
14 * @package CRM
15 * @copyright CiviCRM LLC https://civicrm.org/licensing
16 */
17
18 /**
19 * Class that uses google geocoder
20 */
21 class CRM_Utils_Geocode_Google {
22
23 /**
24 * Server to retrieve the lat/long
25 *
26 * @var string
27 */
28 static protected $_server = 'maps.googleapis.com';
29
30 /**
31 * Uri of service.
32 *
33 * @var string
34 */
35 static protected $_uri = '/maps/api/geocode/xml?sensor=false&address=';
36
37 /**
38 * Function that takes an address object and gets the latitude / longitude for this
39 * address. Note that at a later stage, we could make this function also clean up
40 * the address into a more valid format
41 *
42 * @param array $values
43 * @param bool $stateName
44 *
45 * @return bool
46 * true if we modified the address, false otherwise
47 */
48 public static function format(&$values, $stateName = FALSE) {
49 // we need a valid country, else we ignore
50 if (empty($values['country'])) {
51 return FALSE;
52 }
53
54 $config = CRM_Core_Config::singleton();
55
56 $add = '';
57
58 if (!empty($values['street_address'])) {
59 $add = urlencode(str_replace('', '+', $values['street_address']));
60 $add .= ',+';
61 }
62
63 $city = $values['city'] ?? NULL;
64 if ($city) {
65 $add .= '+' . urlencode(str_replace('', '+', $city));
66 $add .= ',+';
67 }
68
69 if (!empty($values['state_province']) || (!empty($values['state_province_id']) && $values['state_province_id'] != 'null')) {
70 if (!empty($values['state_province_id'])) {
71 $stateProvince = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_StateProvince', $values['state_province_id']);
72 }
73 else {
74 if (!$stateName) {
75 $stateProvince = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_StateProvince',
76 $values['state_province'],
77 'name',
78 'abbreviation'
79 );
80 }
81 else {
82 $stateProvince = $values['state_province'];
83 }
84 }
85
86 // dont add state twice if replicated in city (happens in NZ and other countries, CRM-2632)
87 if ($stateProvince != $city) {
88 $add .= '+' . urlencode(str_replace('', '+', $stateProvince));
89 $add .= ',+';
90 }
91 }
92
93 if (!empty($values['postal_code'])) {
94 $add .= '+' . urlencode(str_replace('', '+', $values['postal_code']));
95 $add .= ',+';
96 }
97
98 if (!empty($values['country'])) {
99 $add .= '+' . urlencode(str_replace('', '+', $values['country']));
100 }
101
102 if (!empty($config->geoAPIKey)) {
103 $add .= '&key=' . urlencode($config->geoAPIKey);
104 }
105
106 $query = 'https://' . self::$_server . self::$_uri . $add;
107
108 $client = new GuzzleHttp\Client();
109 $request = $client->request('GET', $query);
110 $string = $request->getBody();
111
112 libxml_use_internal_errors(TRUE);
113 $xml = @simplexml_load_string($string);
114 CRM_Utils_Hook::geocoderFormat('Google', $values, $xml);
115 if ($xml === FALSE) {
116 // account blocked maybe?
117 CRM_Core_Error::debug_var('Geocoding failed. Message from Google:', $string);
118 return FALSE;
119 }
120
121 if (isset($xml->status)) {
122 if ($xml->status == 'OK' &&
123 is_a($xml->result->geometry->location,
124 'SimpleXMLElement'
125 )
126 ) {
127 $ret = $xml->result->geometry->location->children();
128 if ($ret->lat && $ret->lng) {
129 $values['geo_code_1'] = (float) $ret->lat;
130 $values['geo_code_2'] = (float) $ret->lng;
131 return TRUE;
132 }
133 }
134 elseif ($xml->status == 'ZERO_RESULTS') {
135 // reset the geo code values if we did not get any good values
136 $values['geo_code_1'] = $values['geo_code_2'] = 'null';
137 return FALSE;
138 }
139 else {
140 CRM_Core_Error::debug_var("Geocoding failed. Message from Google: ({$xml->status})", (string ) $xml->error_message);
141 $values['geo_code_1'] = $values['geo_code_2'] = 'null';
142 $values['geo_code_error'] = $xml->status;
143 return FALSE;
144 }
145 }
146 }
147
148 }