/** * Add an Address for a contact. * * FIXME: Should be using basic_create util * * @param array $params * Array per getfields metadata. * * @return array * API result array */ function civicrm_api3_address_create(&$params) { _civicrm_api3_check_edit_permissions('CRM_Core_BAO_Address', $params); /** * If street_parsing, street_address has to be parsed into * separate parts */ if (array_key_exists('street_parsing', $params)) { if ($params['street_parsing'] == 1) { if (array_key_exists('street_address', $params)) { if (!empty($params['street_address'])) { $parsedItems = CRM_Core_BAO_Address::parseStreetAddress($params['street_address']); if (array_key_exists('street_name', $parsedItems)) { $params['street_name'] = $parsedItems['street_name']; } if (array_key_exists('street_unit', $parsedItems)) { $params['street_unit'] = $parsedItems['street_unit']; } if (array_key_exists('street_number', $parsedItems)) { $params['street_number'] = $parsedItems['street_number']; } if (array_key_exists('street_number_suffix', $parsedItems)) { $params['street_number_suffix'] = $parsedItems['street_number_suffix']; } } } } } if (!isset($params['check_permissions'])) { $params['check_permissions'] = 0; } /** * Create array for BAO (expects address params in as an * element in array 'address' */ $addressBAO = CRM_Core_BAO_Address::add($params, TRUE); if (empty($addressBAO)) { return civicrm_api3_create_error("Address is not created or updated "); } else { $values = _civicrm_api3_dao_to_array($addressBAO, $params); return civicrm_api3_create_success($values, $params, 'Address', $addressBAO); } }
/** * Parse all address blocks present in given params * and return parse result for all address blocks, * This function either parse street address in to child * elements or build street address from child elements. * * @param array $params * of key value consist of address blocks. * * @return array * as array of success/fails for each address block */ public function parseAddress(&$params) { $parseSuccess = $parsedFields = array(); if (!is_array($params['address']) || CRM_Utils_System::isNull($params['address'])) { return $parseSuccess; } foreach ($params['address'] as $instance => &$address) { $buildStreetAddress = FALSE; $parseFieldName = 'street_address'; foreach (array('street_number', 'street_name', 'street_unit') as $fld) { if (!empty($address[$fld])) { $parseFieldName = 'street_number'; $buildStreetAddress = TRUE; break; } } // main parse string. $parseString = CRM_Utils_Array::value($parseFieldName, $address); // parse address field. $parsedFields = CRM_Core_BAO_Address::parseStreetAddress($parseString); if ($buildStreetAddress) { //hack to ignore spaces between number and suffix. //here user gives input as street_number so it has to //be street_number and street_number_suffix, but //due to spaces though preg detect string as street_name //consider it as 'street_number_suffix'. $suffix = $parsedFields['street_number_suffix']; if (!$suffix) { $suffix = $parsedFields['street_name']; } $address['street_number_suffix'] = $suffix; $address['street_number'] = $parsedFields['street_number']; $streetAddress = NULL; foreach (array('street_number', 'street_number_suffix', 'street_name', 'street_unit') as $fld) { if (in_array($fld, array('street_name', 'street_unit'))) { $streetAddress .= ' '; } $streetAddress .= CRM_Utils_Array::value($fld, $address); } $address['street_address'] = trim($streetAddress); $parseSuccess[$instance] = TRUE; } else { $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; } // check for original street address string. if (empty($parseString)) { $success = TRUE; } $parseSuccess[$instance] = $success; // we do not reset element values, but keep what we've parsed // in case of partial matches: CRM-8378 // merge parse address in to main address block. $address = array_merge($address, $parsedFields); } } return $parseSuccess; }
/** * format common params data to proper format to store. * * @param array $params contain record values. * @param array $formatted array of formatted data. * @param array $contactFields contact DAO fields. * @static */ function formatCommonData($params, &$formatted, &$contactFields) { $csType = array(CRM_Utils_Array::value('contact_type', $formatted)); //CRM-5125 //add custom fields for contact sub type if (!empty($this->_contactSubType)) { $csType = $this->_contactSubType; } if ($relCsType = CRM_Utils_Array::value('contact_sub_type', $formatted)) { $csType = $relCsType; } $customFields = CRM_Core_BAO_CustomField::getFields($formatted['contact_type'], false, false, $csType); //if a Custom Email Greeting, Custom Postal Greeting or Custom Addressee is mapped, and no "Greeting / Addressee Type ID" is provided, then automatically set the type = Customized, CRM-4575 $elements = array('email_greeting_custom' => 'email_greeting', 'postal_greeting_custom' => 'postal_greeting', 'addressee_custom' => 'addressee'); foreach ($elements as $k => $v) { if (array_key_exists($k, $params) && !array_key_exists($v, $params)) { $label = key(CRM_Core_OptionGroup::values($v, true, null, null, 'AND v.name = "Customized"')); $params[$v] = $label; } } //format date first $session =& CRM_Core_Session::singleton(); $dateType = $session->get("dateTypes"); foreach ($params as $key => $val) { if ($customFieldID = CRM_Core_BAO_CustomField::getKeyID($key)) { //we should not update Date to null, CRM-4062 if ($val && $customFields[$customFieldID]['data_type'] == 'Date') { self::formatCustomDate($params, $formatted, $dateType, $key); unset($params[$key]); } else { if ($customFields[$customFieldID]['data_type'] == 'Boolean') { $params[$key] = CRM_Utils_String::strtoboolstr($val); } } } if ($key == 'birth_date' && $val) { CRM_Utils_Date::convertToDefaultDate($params, $dateType, $key); } else { if ($key == 'deceased_date' && $val) { CRM_Utils_Date::convertToDefaultDate($params, $dateType, $key); } else { if ($key == 'is_deceased' && $val) { $params[$key] = CRM_Utils_String::strtoboolstr($val); } else { if ($key == 'gender') { //CRM-4360 $params[$key] = $this->checkGender($val); } } } } } //now format custom data. foreach ($params as $key => $field) { if ($field == null || $field === '') { continue; } if (is_array($field)) { foreach ($field as $value) { $break = false; if (is_array($value)) { foreach ($value as $name => $testForEmpty) { // check if $value does not contain IM provider or phoneType if (($name !== 'phone_type_id' || $name !== 'provider_id') && ($testForEmpty === '' || $testForEmpty == null)) { $break = true; break; } } } else { $break = true; } if (!$break) { _civicrm_add_formatted_param($value, $formatted); } } continue; } $formatValues = array($key => $field); if ($key !== 'preferred_communication_method' && array_key_exists($key, $contactFields)) { // due to merging of individual table and // contact table, we need to avoid // preferred_communication_method forcefully $formatValues['contact_type'] = $formatted['contact_type']; } if ($key == 'id' && isset($field)) { $formatted[$key] = $field; } _civicrm_add_formatted_param($formatValues, $formatted); //Handling Custom Data if (($customFieldID = CRM_Core_BAO_CustomField::getKeyID($key)) && array_key_exists($customFieldID, $customFields)) { //get the html type. $type = $customFields[$customFieldID]['html_type']; switch ($type) { case 'CheckBox': case 'AdvMulti-Select': case 'Multi-Select': $mulValues = explode(',', $field); $customOption = CRM_Core_BAO_CustomOption::getCustomOption($customFieldID, true); $formatted[$key] = array(); foreach ($mulValues as $v1) { foreach ($customOption as $v2) { if (strtolower($v2['label']) == strtolower(trim($v1)) || strtolower($v2['value']) == strtolower(trim($v1))) { if ($type == 'CheckBox') { $formatted[$key][$v2['value']] = 1; } else { $formatted[$key][] = $v2['value']; } } } } break; case 'Select': case 'Radio': $customOption = CRM_Core_BAO_CustomOption::getCustomOption($customFieldID, true); foreach ($customOption as $v2) { if (strtolower($v2['label']) == strtolower(trim($field)) || strtolower($v2['value']) == strtolower(trim($field))) { $formatted[$key] = $v2['value']; } } break; case 'Multi-Select State/Province': $mulValues = explode(',', $field); $stateAbbr = CRM_Core_PseudoConstant::stateProvinceAbbreviation(); $stateName = CRM_Core_PseudoConstant::stateProvince(); $formatted[$key] = $stateValues = array(); foreach ($mulValues as $values) { if ($val = CRM_Utils_Array::key($values, $stateAbbr)) { $formatted[$key][] = $val; } else { if ($val = CRM_Utils_Array::key($values, $stateName)) { $formatted[$key][] = $val; } } } break; case 'Multi-Select Country': $config =& CRM_Core_Config::singleton(); $limitCodes = $config->countryLimit(); $mulValues = explode(',', $field); $formatted[$key] = array(); CRM_Core_PseudoConstant::populate($countryNames, 'CRM_Core_DAO_Country', true, 'name', 'is_active'); CRM_Core_PseudoConstant::populate($countryIsoCodes, 'CRM_Core_DAO_Country', true, 'iso_code'); foreach ($mulValues as $values) { if ($val = CRM_Utils_Array::key($values, $countryNames)) { $formatted[$key][] = $val; } else { if ($val = CRM_Utils_Array::key($values, $countryIsoCodes)) { $formatted[$key][] = $val; } else { if ($val = CRM_Utils_Array::key($values, $limitCodes)) { $formatted[$key][] = $val; } } } } break; } } } // check for primary location type, whether it is already present for the contact or not, CRM-4423 if (CRM_Utils_Array::value('id', $formatted) && isset($formatted['location'])) { $primaryLocationTypeId = CRM_Contact_BAO_Contact::getPrimaryLocationType($formatted['id'], true); if (isset($primaryLocationTypeId)) { foreach ($formatted['location'] as $loc => $details) { if ($primaryLocationTypeId == CRM_Utils_Array::value('location_type_id', $details)) { $formatted['location'][$loc]['is_primary'] = 1; break; } else { $formatted['location'][$loc]['is_primary'] = 0; } } } } // parse street address, CRM-5450 if ($this->_parseStreetAddress) { require_once 'CRM/Core/BAO/Address.php'; if (array_key_exists('address', $formatted) && is_array($formatted['address'])) { foreach ($formatted['address'] as $instance => &$address) { $streetAddress = CRM_Utils_Array::value('street_address', $address); if (empty($streetAddress)) { continue; } // parse address field. $parsedFields = CRM_Core_BAO_Address::parseStreetAddress($streetAddress); //street address consider to be parsed properly, //If we get street_name and street_number. if (!CRM_Utils_Array::value('street_name', $parsedFields) || !CRM_Utils_Array::value('street_number', $parsedFields)) { $parsedFields = array_fill_keys(array_keys($parsedFields), ''); } // merge parse address w/ main address block. $address = array_merge($address, $parsedFields); } } } }
/** * Parse street address. * * @param array $contactValues * Contact values. * @param CRM_Core_Form $form * Form object. */ public static function parseStreetAddress(&$contactValues, &$form) { if (!is_array($contactValues) || !is_array($form->_fields)) { return; } static $parseAddress; $addressFldKey = 'street_address'; if (!isset($parseAddress)) { $parseAddress = FALSE; foreach ($form->_fields as $key => $fld) { if (strpos($key, $addressFldKey) !== FALSE) { $parseAddress = CRM_Utils_Array::value('street_address_parsing', CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'address_options'), FALSE); break; } } } if (!$parseAddress) { return; } $allParseValues = array(); foreach ($contactValues as $key => $value) { if (strpos($key, $addressFldKey) !== FALSE) { $locTypeId = substr($key, strlen($addressFldKey) + 1); // parse address field. $parsedFields = CRM_Core_BAO_Address::parseStreetAddress($value); //street address consider to be parsed properly, //If we get street_name and street_number. if (empty($parsedFields['street_name']) || empty($parsedFields['street_number'])) { $parsedFields = array_fill_keys(array_keys($parsedFields), ''); } //merge parse values. foreach ($parsedFields as $fldKey => $parseVal) { if ($locTypeId) { $fldKey .= "-{$locTypeId}"; } $allParseValues[$fldKey] = $parseVal; } } } //finally merge all parse values if (!empty($allParseValues)) { $contactValues += $allParseValues; } }
/** * Format the address params to have reasonable values. * * @param array $params * (reference ) an assoc array of name/value pairs. */ public static function fixAddress(&$params) { if (!empty($params['billing_street_address'])) { //Check address is coming from online contribution / registration page //Fixed :CRM-5076 $billing = array('street_address' => 'billing_street_address', 'city' => 'billing_city', 'postal_code' => 'billing_postal_code', 'state_province' => 'billing_state_province', 'state_province_id' => 'billing_state_province_id', 'country' => 'billing_country', 'country_id' => 'billing_country_id'); foreach ($billing as $key => $val) { if ($value = CRM_Utils_Array::value($val, $params)) { if (!empty($params[$key])) { unset($params[$val]); } else { //add new key and removed old $params[$key] = $value; unset($params[$val]); } } } } /* Split the zip and +4, if it's in US format */ if (!empty($params['postal_code']) && preg_match('/^(\\d{4,5})[+-](\\d{4})$/', $params['postal_code'], $match)) { $params['postal_code'] = $match[1]; $params['postal_code_suffix'] = $match[2]; } // add country id if not set if ((!isset($params['country_id']) || !is_numeric($params['country_id'])) && isset($params['country'])) { $country = new CRM_Core_DAO_Country(); $country->name = $params['country']; if (!$country->find(TRUE)) { $country->name = NULL; $country->iso_code = $params['country']; $country->find(TRUE); } $params['country_id'] = $country->id; } // add state_id if state is set if ((!isset($params['state_province_id']) || !is_numeric($params['state_province_id'])) && isset($params['state_province'])) { if (!empty($params['state_province'])) { $state_province = new CRM_Core_DAO_StateProvince(); $state_province->name = $params['state_province']; // add country id if present if (!empty($params['country_id'])) { $state_province->country_id = $params['country_id']; } if (!$state_province->find(TRUE)) { unset($state_province->name); $state_province->abbreviation = $params['state_province']; $state_province->find(TRUE); } $params['state_province_id'] = $state_province->id; if (empty($params['country_id'])) { // set this here since we have it $params['country_id'] = $state_province->country_id; } } else { $params['state_province_id'] = 'null'; } } // add county id if county is set // CRM-7837 if ((!isset($params['county_id']) || !is_numeric($params['county_id'])) && isset($params['county']) && !empty($params['county'])) { $county = new CRM_Core_DAO_County(); $county->name = $params['county']; if (isset($params['state_province_id'])) { $county->state_province_id = $params['state_province_id']; } if ($county->find(TRUE)) { $params['county_id'] = $county->id; } } // currently copy values populates empty fields with the string "null" // and hence need to check for the string null if (isset($params['state_province_id']) && is_numeric($params['state_province_id']) && (!isset($params['country_id']) || empty($params['country_id']))) { // since state id present and country id not present, hence lets populate it // jira issue http://issues.civicrm.org/jira/browse/CRM-56 $params['country_id'] = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_StateProvince', $params['state_province_id'], 'country_id'); } //special check to ignore non numeric values if they are not //detected by formRule(sometimes happens due to internet latency), also allow user to unselect state/country if (isset($params['state_province_id'])) { if (empty($params['state_province_id'])) { $params['state_province_id'] = 'null'; } elseif (!is_numeric($params['state_province_id']) || (int) $params['state_province_id'] < 1000) { // CRM-3393 ( the hacky 1000 check) $params['state_province_id'] = 'null'; } } if (isset($params['country_id'])) { if (empty($params['country_id'])) { $params['country_id'] = 'null'; } elseif (!is_numeric($params['country_id']) || (int) $params['country_id'] < 1000) { // CRM-3393 ( the hacky 1000 check) $params['country_id'] = 'null'; } } // add state and country names from the ids if (isset($params['state_province_id']) && is_numeric($params['state_province_id'])) { $params['state_province'] = CRM_Core_PseudoConstant::stateProvinceAbbreviation($params['state_province_id']); } if (isset($params['country_id']) && is_numeric($params['country_id'])) { $params['country'] = CRM_Core_PseudoConstant::country($params['country_id']); } $config = CRM_Core_Config::singleton(); $asp = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::ADDRESS_STANDARDIZATION_PREFERENCES_NAME, 'address_standardization_provider'); // clean up the address via USPS web services if enabled if ($asp === 'USPS' && $params['country_id'] == 1228) { CRM_Utils_Address_USPS::checkAddress($params); // do street parsing again if enabled, since street address might have changed $parseStreetAddress = CRM_Utils_Array::value('street_address_parsing', CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'address_options'), FALSE); if ($parseStreetAddress && !empty($params['street_address'])) { foreach (array('street_number', 'street_name', 'street_unit', 'street_number_suffix') as $fld) { unset($params[$fld]); } // main parse string. $parseString = CRM_Utils_Array::value('street_address', $params); $parsedFields = CRM_Core_BAO_Address::parseStreetAddress($parseString); // merge parse address in to main address block. $params = array_merge($params, $parsedFields); } } // add latitude and longitude and format address if needed if (!empty($config->geocodeMethod) && $config->geocodeMethod != 'CRM_Utils_Geocode_OpenStreetMaps' && empty($params['manual_geo_code'])) { $class = $config->geocodeMethod; $class::format($params); } }
/** * ParseStreetAddress() method (get street address parsed) */ public function testParseStreetAddress() { // valid Street address to be parsed ( without locale ) $street_address = "54A Excelsior Ave. Apt 1C"; $parsedStreetAddress = CRM_Core_BAO_Address::parseStreetAddress($street_address); $this->assertEquals($parsedStreetAddress['street_name'], 'Excelsior Ave.'); $this->assertEquals($parsedStreetAddress['street_unit'], 'Apt 1C'); $this->assertEquals($parsedStreetAddress['street_number'], '54'); $this->assertEquals($parsedStreetAddress['street_number_suffix'], 'A'); // valid Street address to be parsed ( $locale = 'en_US' ) $street_address = "54A Excelsior Ave. Apt 1C"; $locale = 'en_US'; $parsedStreetAddress = CRM_Core_BAO_Address::parseStreetAddress($street_address, $locale); $this->assertEquals($parsedStreetAddress['street_name'], 'Excelsior Ave.'); $this->assertEquals($parsedStreetAddress['street_unit'], 'Apt 1C'); $this->assertEquals($parsedStreetAddress['street_number'], '54'); $this->assertEquals($parsedStreetAddress['street_number_suffix'], 'A'); // invalid Street address ( $locale = 'en_US' ) $street_address = "West St. Apt 1"; $locale = 'en_US'; $parsedStreetAddress = CRM_Core_BAO_Address::parseStreetAddress($street_address, $locale); $this->assertEquals($parsedStreetAddress['street_name'], 'West St.'); $this->assertEquals($parsedStreetAddress['street_unit'], 'Apt 1'); $this->assertNotContains('street_number', $parsedStreetAddress); $this->assertNotContains('street_number_suffix', $parsedStreetAddress); // valid Street address to be parsed ( $locale = 'fr_CA' ) $street_address = "2-123CA Main St"; $locale = 'fr_CA'; $parsedStreetAddress = CRM_Core_BAO_Address::parseStreetAddress($street_address, $locale); $this->assertEquals($parsedStreetAddress['street_name'], 'Main St'); $this->assertEquals($parsedStreetAddress['street_unit'], '2'); $this->assertEquals($parsedStreetAddress['street_number'], '123'); $this->assertEquals($parsedStreetAddress['street_number_suffix'], 'CA'); // invalid Street address ( $locale = 'fr_CA' ) $street_address = "123 Main St"; $locale = 'fr_CA'; $parsedStreetAddress = CRM_Core_BAO_Address::parseStreetAddress($street_address, $locale); $this->assertEquals($parsedStreetAddress['street_name'], 'Main St'); $this->assertEquals($parsedStreetAddress['street_number'], '123'); $this->assertNotContains('street_unit', $parsedStreetAddress); $this->assertNotContains('street_number_suffix', $parsedStreetAddress); }
function processContacts(&$config, $processGeocode, $parseStreetAddress, $start = null, $end = null) { // build where clause. $clause = array('( c.id = a.contact_id )'); if ($start) { $clause[] = "( c.id >= {$start} )"; } if ($end) { $clause[] = "( c.id <= {$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 = "\nSELECT c.id,\n a.id as address_id,\n a.street_address,\n a.city,\n a.postal_code,\n s.name as state,\n o.name as country\nFROM civicrm_contact c\nINNER JOIN civicrm_address a ON a.contact_id = c.id\nLEFT JOIN civicrm_country o ON a.country_id = o.id\nLEFT JOIN civicrm_state_province s ON a.state_province_id = s.id\nWHERE {$whereClause}\n ORDER BY a.id\n"; $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'; } require_once 'CRM/Core/DAO/Address.php'; require_once 'CRM/Core/BAO/Address.php'; 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 (defined('THROTTLE_REQUESTS') && THROTTLE_REQUESTS) { usleep(50000); } eval($config->geocodeMethod . '::format( $params, true );'); array_shift($params); $maxTries--; } while (!isset($params['geo_code_1']) && $maxTries > 1); if (isset($params['geo_code_1'])) { $totalGeocoded++; $addressParams['geo_code_1'] = $params['geo_code_1']; $addressParams['geo_code_2'] = $params['geo_code_2']; } } // 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 (!CRM_Utils_Array::value('street_name', $parsedFields) || !CRM_Utils_Array::value('street_number', $parsedFields)) { $success = false; } // do check for all elements. if ($success) { $totalAddressParsed++; } else { // 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(); } } echo ts("Addresses Evaluated: {$totalAddresses}\n"); if ($processGeocode) { echo ts("Addresses Geocoded : {$totalGeocoded}\n"); } if ($parseStreetAddress) { echo ts("Street Address Parsed : {$totalAddressParsed}\n"); } return; }
/** * Format common params data to proper format to store. * * @param array $params * Contain record values. * @param array $formatted * Array of formatted data. * @param array $contactFields * Contact DAO fields. */ public function formatCommonData($params, &$formatted, &$contactFields) { $csType = array(CRM_Utils_Array::value('contact_type', $formatted)); //CRM-5125 //add custom fields for contact sub type if (!empty($this->_contactSubType)) { $csType = $this->_contactSubType; } if ($relCsType = CRM_Utils_Array::value('contact_sub_type', $formatted)) { $csType = $relCsType; } $customFields = CRM_Core_BAO_CustomField::getFields($formatted['contact_type'], FALSE, FALSE, $csType); $addressCustomFields = CRM_Core_BAO_CustomField::getFields('Address'); $customFields = $customFields + $addressCustomFields; //if a Custom Email Greeting, Custom Postal Greeting or Custom Addressee is mapped, and no "Greeting / Addressee Type ID" is provided, then automatically set the type = Customized, CRM-4575 $elements = array('email_greeting_custom' => 'email_greeting', 'postal_greeting_custom' => 'postal_greeting', 'addressee_custom' => 'addressee'); foreach ($elements as $k => $v) { if (array_key_exists($k, $params) && !array_key_exists($v, $params)) { $label = key(CRM_Core_OptionGroup::values($v, TRUE, NULL, NULL, 'AND v.name = "Customized"')); $params[$v] = $label; } } //format date first $session = CRM_Core_Session::singleton(); $dateType = $session->get("dateTypes"); foreach ($params as $key => $val) { $customFieldID = CRM_Core_BAO_CustomField::getKeyID($key); if ($customFieldID && !array_key_exists($customFieldID, $addressCustomFields)) { //we should not update Date to null, CRM-4062 if ($val && $customFields[$customFieldID]['data_type'] == 'Date') { self::formatCustomDate($params, $formatted, $dateType, $key); } elseif ($customFields[$customFieldID]['data_type'] == 'Boolean') { if (empty($val) && !is_numeric($val) && $this->_onDuplicate == CRM_Import_Parser::DUPLICATE_FILL) { //retain earlier value when Import mode is `Fill` unset($params[$key]); } else { $params[$key] = CRM_Utils_String::strtoboolstr($val); } } if ($key == 'birth_date' && $val) { CRM_Utils_Date::convertToDefaultDate($params, $dateType, $key); } elseif ($key == 'deceased_date' && $val) { CRM_Utils_Date::convertToDefaultDate($params, $dateType, $key); } elseif ($key == 'is_deceased' && $val) { $params[$key] = CRM_Utils_String::strtoboolstr($val); } elseif ($key == 'gender') { //CRM-4360 $params[$key] = $this->checkGender($val); } } } //now format custom data. foreach ($params as $key => $field) { if (is_array($field)) { $isAddressCustomField = FALSE; foreach ($field as $value) { $break = FALSE; if (is_array($value)) { foreach ($value as $name => $testForEmpty) { if ($addressCustomFieldID = CRM_Core_BAO_CustomField::getKeyID($name)) { $isAddressCustomField = TRUE; break; } // check if $value does not contain IM provider or phoneType if (($name !== 'phone_type_id' || $name !== 'provider_id') && ($testForEmpty === '' || $testForEmpty == NULL)) { $break = TRUE; break; } } } else { $break = TRUE; } if (!$break) { require_once 'CRM/Utils/DeprecatedUtils.php'; _civicrm_api3_deprecated_add_formatted_param($value, $formatted); } } if (!$isAddressCustomField) { continue; } } $formatValues = array($key => $field); if ($key !== 'preferred_communication_method' && array_key_exists($key, $contactFields)) { // due to merging of individual table and // contact table, we need to avoid // preferred_communication_method forcefully $formatValues['contact_type'] = $formatted['contact_type']; } if ($key == 'id' && isset($field)) { $formatted[$key] = $field; } require_once 'CRM/Utils/DeprecatedUtils.php'; _civicrm_api3_deprecated_add_formatted_param($formatValues, $formatted); //Handling Custom Data // note: Address custom fields will be handled separately inside _civicrm_api3_deprecated_add_formatted_param if (($customFieldID = CRM_Core_BAO_CustomField::getKeyID($key)) && array_key_exists($customFieldID, $customFields) && !array_key_exists($customFieldID, $addressCustomFields)) { $extends = CRM_Utils_Array::value('extends', $customFields[$customFieldID]); $htmlType = CRM_Utils_Array::value('html_type', $customFields[$customFieldID]); switch ($htmlType) { case 'Select': case 'Radio': case 'Autocomplete-Select': if ($customFields[$customFieldID]['data_type'] == 'String') { $customOption = CRM_Core_BAO_CustomOption::getCustomOption($customFieldID, TRUE); foreach ($customOption as $customFldID => $customValue) { $val = CRM_Utils_Array::value('value', $customValue); $label = CRM_Utils_Array::value('label', $customValue); $label = strtolower($label); $value = strtolower(trim($formatted[$key])); if ($value == $label || $value == strtolower($val)) { $params[$key] = $formatted[$key] = $val; } } } break; case 'CheckBox': case 'AdvMulti-Select': case 'Multi-Select': if (!empty($formatted[$key]) && !empty($params[$key])) { $mulValues = explode(',', $formatted[$key]); $customOption = CRM_Core_BAO_CustomOption::getCustomOption($customFieldID, TRUE); $formatted[$key] = array(); $params[$key] = array(); foreach ($mulValues as $v1) { foreach ($customOption as $v2) { if (strtolower($v2['label']) == strtolower(trim($v1)) || strtolower($v2['value']) == strtolower(trim($v1))) { if ($htmlType == 'CheckBox') { $params[$key][$v2['value']] = $formatted[$key][$v2['value']] = 1; } else { $params[$key][] = $formatted[$key][] = $v2['value']; } } } } } break; } } } if (($customFieldID = CRM_Core_BAO_CustomField::getKeyID($key)) && array_key_exists($customFieldID, $customFields) && !array_key_exists($customFieldID, $addressCustomFields)) { // @todo calling api functions directly is not supported _civicrm_api3_custom_format_params($params, $formatted, $extends); } // to check if not update mode and unset the fields with empty value. if (!$this->_updateWithId && array_key_exists('custom', $formatted)) { foreach ($formatted['custom'] as $customKey => $customvalue) { if (empty($formatted['custom'][$customKey][-1]['is_required'])) { $formatted['custom'][$customKey][-1]['is_required'] = $customFields[$customKey]['is_required']; } $emptyValue = CRM_Utils_Array::value('value', $customvalue[-1]); if (!isset($emptyValue)) { unset($formatted['custom'][$customKey]); } } } // parse street address, CRM-5450 if ($this->_parseStreetAddress) { if (array_key_exists('address', $formatted) && is_array($formatted['address'])) { foreach ($formatted['address'] as $instance => &$address) { $streetAddress = CRM_Utils_Array::value('street_address', $address); if (empty($streetAddress)) { continue; } // parse address field. $parsedFields = CRM_Core_BAO_Address::parseStreetAddress($streetAddress); //street address consider to be parsed properly, //If we get street_name and street_number. if (empty($parsedFields['street_name']) || empty($parsedFields['street_number'])) { $parsedFields = array_fill_keys(array_keys($parsedFields), ''); } // merge parse address w/ main address block. $address = array_merge($address, $parsedFields); } } } }
/** * @param $config * @param $processGeocode * @param $parseStreetAddress * * @return array * @throws Exception */ public function processContacts(&$config, $processGeocode, $parseStreetAddress) { // build where clause. $clause = array('( c.id = a.contact_id )'); $params = array(); if ($this->start) { $clause[] = "( c.id >= %1 )"; $params[1] = array($this->start, 'Integer'); } if ($this->end) { $clause[] = "( c.id <= %2 )"; $params[2] = array($this->end, 'Integer'); } 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 = "\n SELECT c.id,\n a.id as address_id,\n a.street_address,\n a.city,\n a.postal_code,\n s.name as state,\n o.name as country\n FROM civicrm_contact c\n INNER JOIN civicrm_address a ON a.contact_id = c.id\n LEFT JOIN civicrm_country o ON a.country_id = o.id\n LEFT JOIN civicrm_state_province s ON a.state_province_id = s.id\n WHERE {$whereClause}\n ORDER BY a.id\n "; $totalGeocoded = $totalAddresses = $totalAddressParsed = 0; $dao = CRM_Core_DAO::executeQuery($query, $params); 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'] = CRM_Utils_Array::value('postal_code_suffix', $params); } } // 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 . " <a href =\"{$url}\"> " . $dao->street_address . " </a> "; // 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[] = "<br />\n" . ts("Following is the list of contacts whose address is not parsed:") . "<br />\n"; foreach ($unparseableContactAddress as $contactLink) { $this->returnMessages[] = $contactLink . "<br />\n"; } } } return $this->returnResult(); }
/** * @param $config * @param $processGeocode * @param $parseStreetAddress * @param null $start * @param null $end */ function processContacts(&$config, $processGeocode, $parseStreetAddress, $start = NULL, $end = NULL) { // build where clause. $clause = array('( c.id = a.contact_id )'); if ($start) { $clause[] = "( c.id >= {$start} )"; } if ($end) { $clause[] = "( c.id <= {$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 = "\nSELECT c.id,\n a.id as address_id,\n a.street_address,\n a.city,\n a.postal_code,\n s.name as state,\n o.name as country\nFROM civicrm_contact c\nINNER JOIN civicrm_address a ON a.contact_id = c.id\nLEFT JOIN civicrm_country o ON a.country_id = o.id\nLEFT JOIN civicrm_state_province s ON a.state_province_id = s.id\nWHERE {$whereClause}\n ORDER BY a.id\n"; $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'; } require_once 'CRM/Core/DAO/Address.php'; require_once 'CRM/Core/BAO/Address.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 (defined('THROTTLE_REQUESTS') && THROTTLE_REQUESTS) { usleep(50000); } eval($config->geocodeMethod . '::format( $params, true );'); array_shift($params); $maxTries--; } while (!isset($params['geo_code_1']) && $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']; } } // 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 . " <a href =\"{$url}\"> " . $dao->street_address . " </a> "; // 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(); } } echo ts("Addresses Evaluated: {$totalAddresses}\n"); if ($processGeocode) { echo ts("Addresses Geocoded : {$totalGeocoded}\n"); } if ($parseStreetAddress) { echo ts("Street Address Parsed : {$totalAddressParsed}\n"); if ($unparseableContactAddress) { echo ts("<br />\nFollowing is the list of contacts whose address is not parsed :<br />\n"); foreach ($unparseableContactAddress as $contactLink) { echo ts("%1<br />\n", array(1 => $contactLink)); } } } }
function parseAddress(&$params) { $parseSuccess = $parsedFields = array(); if (!is_array($params['address']) || CRM_Utils_System::isNull($params['address'])) { return $parseSuccess; } require_once 'CRM/Core/BAO/Address.php'; $buildStreetAddress = false; foreach ($params['address'] as $instance => &$address) { $parseFieldName = 'street_address'; foreach (array('street_number', 'street_name', 'street_unit') as $fld) { if (CRM_Utils_Array::value($fld, $address)) { $parseFieldName = 'street_number'; $buildStreetAddress = true; break; } } // main parse string. $parseString = CRM_Utils_Array::value($parseFieldName, $address); // parse address field. $parsedFields = CRM_Core_BAO_Address::parseStreetAddress($parseString); if ($buildStreetAddress) { //hack to ignore spaces between number and suffix. //here user gives input as street_number so it has to //be street_number and street_number_suffix, but //due to spaces though preg detect string as street_name //consider it as 'street_number_suffix'. $suffix = $parsedFields['street_number_suffix']; if (!$suffix) { $suffix = $parsedFields['street_name']; } $address['street_number_suffix'] = $suffix; $address['street_number'] = $parsedFields['street_number']; $streetAddress = null; foreach (array('street_number', 'street_number_suffix', 'street_name', 'street_unit') as $fld) { if (in_array($fld, array('street_name', 'street_unit'))) { $streetAddress .= ' '; } $streetAddress .= CRM_Utils_Array::value($fld, $address); } $address['street_address'] = trim($streetAddress); $parseSuccess[$instance] = true; } else { $success = true; // consider address is automatically parseable, // when we should found street_number and street_name if (!CRM_Utils_Array::value('street_name', $parsedFields) || !CRM_Utils_Array::value('street_number', $parsedFields)) { $success = false; } // check for original street address string. if (empty($parseString)) { $success = true; } $parseSuccess[$instance] = $success; // reset element values. if (!$success) { $parsedFields = array_fill_keys(array_keys($parsedFields), ''); } // merge parse address in to main address block. $address = array_merge($address, $parsedFields); } } return $parseSuccess; }