$value) { $this->$name = $value; } // fixme: more params verification } public function run() { $config = &CRM_Core_Config::singleton(); // do check for geocoding. $processGeocode = FALSE; if (empty($config->geocodeMethod)) { if ($this->geocoding == 'true') { $this->returnMessages[] = ts('Error: You need to set a mapping provider under Administer > System Settings > Mapping and Geocoding'); $this->returnError = 1; $this->returnResult(); } } else { $processGeocode = TRUE; // user might want to over-ride. if ($this->geocoding == 'false') { $processGeocode = FALSE; } } // do check for parse street address. $parseAddress = FALSE; $parseAddress = CRM_Utils_Array::value('street_address_parsing', CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'address_options' ), FALSE ); $parseStreetAddress = FALSE; if (!$parseAddress) { if ($this->parse == 'true') { $this->returnMessages[] = ts('Error: You need to enable Street Address Parsing under Administer > Localization > Address Settings.'); $this->returnError = 1; return $this->returnResult(); } } else { $parseStreetAddress = TRUE; // user might want to over-ride. if ($this->parse == 'false') { $parseStreetAddress = FALSE; } } // don't process. if (!$parseStreetAddress && !$processGeocode) { $this->returnMessages[] = ts('Error: Both Geocode mapping as well as Street Address Parsing are disabled. You must configure one or both options to use this script.'); $this->returnError = 1; return $this->returnResult(); } // do check for parse street address. return $this->processContacts($config, $processGeocode, $parseStreetAddress); } function processContacts(&$config, $processGeocode, $parseStreetAddress) { // build where clause. $clause = array('( c.id = a.contact_id )'); if ($this->start) { $clause[] = "( c.id >= $this->start )"; } if ($this->end) { $clause[] = "( c.id <= $this->end )"; } if ($processGeocode) { $clause[] = '( a.geo_code_1 is null OR a.geo_code_1 = 0 )'; $clause[] = '( a.geo_code_2 is null OR a.geo_code_2 = 0 )'; $clause[] = '( a.country_id is not null )'; } $whereClause = implode(' AND ', $clause); $query = " SELECT c.id, a.id as address_id, a.street_address, a.city, a.postal_code, s.name as state, o.name as country FROM civicrm_contact c INNER JOIN civicrm_address a ON a.contact_id = c.id LEFT JOIN civicrm_country o ON a.country_id = o.id LEFT JOIN civicrm_state_province s ON a.state_province_id = s.id WHERE {$whereClause} ORDER BY a.id "; $totalGeocoded = $totalAddresses = $totalAddressParsed = 0; $dao = CRM_Core_DAO::executeQuery($query, CRM_Core_DAO::$_nullArray); if ($processGeocode) { require_once (str_replace('_', DIRECTORY_SEPARATOR, $config->geocodeMethod) . '.php'); } $unparseableContactAddress = array(); while ($dao->fetch()) { $totalAddresses++; $params = array( 'street_address' => $dao->street_address, 'postal_code' => $dao->postal_code, 'city' => $dao->city, 'state_province' => $dao->state, 'country' => $dao->country, ); $addressParams = array(); // process geocode. if ($processGeocode) { // loop through the address removing more information // so we can get some geocode for a partial address // i.e. city -> state -> country $maxTries = 5; do { if ($this->throttle) { usleep(5000000); } $className = $config->geocodeMethod; $className::format( $params, true ); // see if we got a geocode error, in this case we'll trigger a fatal // CRM-13760 if ( isset($params['geo_code_error']) && $params['geo_code_error'] == 'OVER_QUERY_LIMIT' ) { CRM_Core_Error::fatal('Aborting batch geocoding. Hit the over query limit on geocoder.'); } array_shift($params); $maxTries--; } while ( (!isset($params['geo_code_1']) || $params['geo_code_1'] == 'null') && ($maxTries > 1) ); if (isset($params['geo_code_1']) && $params['geo_code_1'] != 'null') { $totalGeocoded++; $addressParams['geo_code_1'] = $params['geo_code_1']; $addressParams['geo_code_2'] = $params['geo_code_2']; $addressParams['postal_code'] = $params['postal_code']; $addressParams['postal_code_suffix'] = $params['postal_code_suffix']; } } // parse street address if ($parseStreetAddress) { $parsedFields = CRM_Core_BAO_Address::parseStreetAddress($dao->street_address); $success = TRUE; // consider address is automatically parseable, // when we should found street_number and street_name if (empty($parsedFields['street_name']) || empty($parsedFields['street_number'])) { $success = FALSE; } // do check for all elements. if ($success) { $totalAddressParsed++; } elseif ($dao->street_address) { //build contact edit url, //so that user can manually fill the street address fields if the street address is not parsed, CRM-5886 $url = CRM_Utils_System::url('civicrm/contact/add', "reset=1&action=update&cid={$dao->id}"); $unparseableContactAddress[] = " Contact ID: " . $dao->id . " " . $dao->street_address . " "; // reset element values. $parsedFields = array_fill_keys(array_keys($parsedFields), ''); } $addressParams = array_merge($addressParams, $parsedFields); } // finally update address object. if (!empty($addressParams)) { $address = new CRM_Core_DAO_Address(); $address->id = $dao->address_id; $address->copyValues($addressParams); $address->save(); $address->free(); } } $this->returnMessages[] = ts("Addresses Evaluated: %1", array( 1 => $totalAddresses)) . "\n"; if ($processGeocode) { $this->returnMessages[] = ts("Addresses Geocoded: %1", array( 1 => $totalGeocoded)) . "\n"; } if ($parseStreetAddress) { $this->returnMessages[] = ts("Street Addresses Parsed: %1", array( 1 => $totalAddressParsed)) . "\n"; if ($unparseableContactAddress) { $this->returnMessages[] = "
\n" . ts("Following is the list of contacts whose address is not parsed:") . "
\n"; foreach ($unparseableContactAddress as $contactLink) { $this->returnMessages[] = $contactLink . "
\n"; } } } return $this->returnResult(); } function returnResult() { $result = array(); $result['is_error'] = $this->returnError; $result['messages'] = implode("", $this->returnMessages); return $result; } }