/** * Delete a contact and all its associated records. * * @param int $id * Id of the contact to delete. * @param bool $restore * Whether to actually restore, not delete. * @param bool $skipUndelete * Whether to force contact delete or not. * * @return bool * Was contact deleted? */ public static function deleteContact($id, $restore = FALSE, $skipUndelete = FALSE) { if (!$id) { return FALSE; } // If trash is disabled in system settings then we always skip if (!CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'contact_undelete', NULL, 1)) { $skipUndelete = TRUE; } // make sure we have edit permission for this contact // before we delete if ($skipUndelete && !CRM_Core_Permission::check('delete contacts') || $restore && !CRM_Core_Permission::check('access deleted contacts')) { return FALSE; } // CRM-12929 // Restrict contact to be delete if contact has financial trxns $error = NULL; if ($skipUndelete && CRM_Financial_BAO_FinancialItem::checkContactPresent(array($id), $error)) { return FALSE; } // make sure this contact_id does not have any membership types $membershipTypeID = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType', $id, 'id', 'member_of_contact_id'); if ($membershipTypeID) { return FALSE; } $contact = new CRM_Contact_DAO_Contact(); $contact->id = $id; if (!$contact->find(TRUE)) { return FALSE; } $contactType = $contact->contact_type; // currently we only clear employer cache. // we are now deleting inherited membership if any. if ($contact->contact_type == 'Organization') { $action = $restore ? CRM_Core_Action::ENABLE : CRM_Core_Action::DISABLE; $relationshipDtls = CRM_Contact_BAO_Relationship::getRelationship($id); if (!empty($relationshipDtls)) { foreach ($relationshipDtls as $rId => $details) { CRM_Contact_BAO_Relationship::disableEnableRelationship($rId, $action); } } CRM_Contact_BAO_Contact_Utils::clearAllEmployee($id); } if ($restore) { return self::contactTrashRestore($contact, TRUE); } // start a new transaction $transaction = new CRM_Core_Transaction(); if ($skipUndelete) { CRM_Utils_Hook::pre('delete', $contactType, $id, CRM_Core_DAO::$_nullArray); //delete billing address if exists. CRM_Contribute_BAO_Contribution::deleteAddress(NULL, $id); // delete the log entries since we dont have triggers enabled as yet $logDAO = new CRM_Core_DAO_Log(); $logDAO->entity_table = 'civicrm_contact'; $logDAO->entity_id = $id; $logDAO->delete(); // delete contact participants CRM-12155 CRM_Event_BAO_Participant::deleteContactParticipant($id); // delete contact contributions CRM-12155 CRM_Contribute_BAO_Contribution::deleteContactContribution($id); // do activity cleanup, CRM-5604 CRM_Activity_BAO_Activity::cleanupActivity($id); // delete all notes related to contact CRM_Core_BAO_Note::cleanContactNotes($id); // delete cases related to contact $contactCases = CRM_Case_BAO_Case::retrieveCaseIdsByContactId($id); if (!empty($contactCases)) { foreach ($contactCases as $caseId) { //check if case is associate with other contact or not. $caseContactId = CRM_Case_BAO_Case::getCaseClients($caseId); if (count($caseContactId) <= 1) { CRM_Case_BAO_Case::deleteCase($caseId); } } } $contact->delete(); } else { self::contactTrashRestore($contact); } //delete the contact id from recently view CRM_Utils_Recent::delContact($id); // Update the group contact cache if ($restore) { CRM_Contact_BAO_GroupContactCache::remove(); } else { CRM_Contact_BAO_GroupContactCache::removeContact($id); } // delete any dupe cache entry CRM_Core_BAO_PrevNextCache::deleteItem($id); $transaction->commit(); if ($skipUndelete) { CRM_Utils_Hook::post('delete', $contactType, $contact->id, $contact); } // also reset the DB_DO global array so we can reuse the memory // http://issues.civicrm.org/jira/browse/CRM-4387 CRM_Core_DAO::freeResult(); return TRUE; }
private function contact_create($mode = 'import') { $this->import_status_update('contact'); // bug fix for $this->contacts keep being appended if (!empty($this->contacts)) { unset($this->contacts); $this->contacts = array(); } for ($i = 0; $i < count($this->csv->data); $i++) { $param = array('version' => '3', 'contact_type' => 'Individual'); if ($mode == 'import') { $param['dupe_check'] = $this->data->dupe_check == 1 ? TRUE : FALSE; // #FIX issue 87: auto-append contact source if it is not mapped // appending the date and the job id to the import if (!in_array('contact_source', $this->contacts)) { $param['contact_source'] = date('Ymd') . '_' . $this->data->jobid; } // #FIX issue 72: Add email only de-dupe feature if ($this->data->dupe_check == 2) { $mapping = array_flip($this->contact_data); $email = $this->csv->data[$i][$mapping['email']]; $contact_id = $this->check_email($email); if (is_numeric($contact_id)) { // for email only dedupe, we delete the param and skip this iteration $this->log->_log('Error on CSV line ' . $i . ':, (Matching contact found:, ' . $contact_id . '),' . implode(',', $this->csv->data[$i]), 'error_csv'); unset($param); continue; } } } // in case we are doing an append with *ONLY* Location data we still need to fill $this->contact if (count($this->contact_data) == 1) { $id = array_values($this->contact_data); $column = array_keys($this->contact_data); if ($id[0] == 'external_identifier') { $contact_id = $this->fetch_contact_id($this->csv->data[$i][$column[0]]); } else { $contact_id = $this->csv->data[$i][$column[0]]; } if (isset($contact_id) && $contact_id != '') { $this->contacts[$contact_id] = $this->csv->data[$i]; } else { // unmatched append row $this->log->_log('Record not found in database:,' . implode(',', $this->csv->data[$i]), 'error_csv'); } } else { foreach ($this->contact_data as $column => $field) { // dealing with some special fields because of CiviCRM's internal workings switch ($field) { case 'birth_date': $param[$field] = civicrm_import_utils::format_date($this->csv->data[$i][$column], $this->data->date_format); break; case 'gender': $param[$field] = civicrm_import_utils::format_gender($this->csv->data[$i][$column]); break; // in appending job you have to get contact_id if they choose to match to external identifier // in appending job you have to get contact_id if they choose to match to external identifier case 'external_identifier': // get the contact id if ($mode == 'import') { $param[$field] = $this->csv->data[$i][$column]; } else { $param['contact_id'] = $this->fetch_contact_id($this->csv->data[$i][$column]); } break; default: $param[$field] = $this->csv->data[$i][$column]; break; } } // print_r($param); // data filtering validation: // if the $param does not fit our validation requirement // i.e. First name, Last name, Email, we do not import them. // #FEATURE: $this->check_filter should return an array of bad fields so we can pin them down in // the log if ($this->check_filter($param, $mode)) { if ($mode == 'import') { // @CiviCRM API (v3) $contact = civicrm_api('contact', 'create', $param); } else { if (isset($param['contact_id']) && $param['contact_id'] != '') { // @CiviCRM API (v3) $param['id'] = $param['contact_id']; unset($param['contact_id']); $contact = civicrm_api('contact', 'create', $param); } else { // log all the ones that did not find a matching record into the error_csv $this->log->_log('Error on CSV line ' . $i . ':, (No matching contact found with the id provided),' . implode(',', $this->csv->data[$i]), 'error_csv'); } } // #FIXED: memory leak from API call CRM_Core_DAO::freeResult(); if ($contact['is_error'] == 1) { $this->log->_log('Error on CSV line ' . $i . ':, (' . $contact['error_message'] . '),' . implode(',', $this->csv->data[$i]), 'error_csv'); } else { $this->contacts[$contact['id']] = $this->csv->data[$i]; $this->contact_imported++; // record the contact import count for tracking if ($this->contact_imported % 100 == 0) { $this->update_count('contact'); } } } else { // log this row as bad row $this->log->_log('Error on CSV line ' . $i . ':, (Bad last name or email on CSV line),' . implode(',', $this->csv->data[$i]), 'error_csv'); } $this->update_count('contact'); } } $this->log->_log($this->contact_imported . ' number of contact records created from ' . count($this->csv->data) . ' number of rows read from CSV file'); // free the original parsed csv from memory unset($this->csv->data); }
/** * @todo Move this to ContactFormat.php * @deprecated */ function civicrm_contact_format_create(&$params) { _civicrm_initialize(); CRM_Core_DAO::freeResult(); // return error if we have no params if (empty($params)) { return civicrm_create_error('Input Parameters empty'); } $error = _civicrm_required_formatted_contact($params); if (civicrm_error($error)) { return $error; } $error = _civicrm_validate_formatted_contact($params); if (civicrm_error($error)) { return $error; } //get the prefix id etc if exists require_once 'CRM/Contact/BAO/Contact.php'; CRM_Contact_BAO_Contact::resolveDefaults($params, TRUE); require_once 'CRM/Import/Parser.php'; if (CRM_Utils_Array::value('onDuplicate', $params) != CRM_Import_Parser::DUPLICATE_NOCHECK) { CRM_Core_Error::reset(); $error = _civicrm_duplicate_formatted_contact($params); if (civicrm_error($error)) { return $error; } } $contact = CRM_Contact_BAO_Contact::create($params, CRM_Utils_Array::value('fixAddress', $params)); _civicrm_object_to_array($contact, $contactArray); return $contactArray; }
/** * A function to build an array of information required by merge function and the merge UI. * * @param int $mainId * Main contact with whom merge has to happen. * @param int $otherId * Duplicate contact which would be deleted after merge operation. * * @return array|bool|int */ public static function getRowsElementsAndInfo($mainId, $otherId) { $qfZeroBug = 'e8cddb72-a257-11dc-b9cc-0016d3330ee9'; // Fetch contacts foreach (array('main' => $mainId, 'other' => $otherId) as $moniker => $cid) { $params = array('contact_id' => $cid, 'version' => 3, 'return' => array_merge(array('display_name'), self::getContactFields())); $result = civicrm_api('contact', 'get', $params); if (empty($result['values'][$cid]['contact_type'])) { return FALSE; } ${$moniker} = $result['values'][$cid]; } static $fields = array(); if (empty($fields)) { $fields = CRM_Contact_DAO_Contact::fields(); CRM_Core_DAO::freeResult(); } // FIXME: there must be a better way foreach (array('main', 'other') as $moniker) { $contact =& ${$moniker}; $preferred_communication_method = CRM_Utils_array::value('preferred_communication_method', $contact); $value = empty($preferred_communication_method) ? array() : $preferred_communication_method; $specialValues[$moniker] = array('preferred_communication_method' => $value, 'communication_style_id' => $value); if (!empty($contact['preferred_communication_method'])) { // api 3 returns pref_comm_method as an array, which breaks the lookup; so we reconstruct $prefCommList = is_array($specialValues[$moniker]['preferred_communication_method']) ? implode(CRM_Core_DAO::VALUE_SEPARATOR, $specialValues[$moniker]['preferred_communication_method']) : $specialValues[$moniker]['preferred_communication_method']; $specialValues[$moniker]['preferred_communication_method'] = CRM_Core_DAO::VALUE_SEPARATOR . $prefCommList . CRM_Core_DAO::VALUE_SEPARATOR; } $names = array('preferred_communication_method' => array('newName' => 'preferred_communication_method_display', 'groupName' => 'preferred_communication_method')); CRM_Core_OptionGroup::lookupValues($specialValues[$moniker], $names); if (!empty($contact['communication_style'])) { $specialValues[$moniker]['communication_style_id_display'] = $contact['communication_style']; } } static $optionValueFields = array(); if (empty($optionValueFields)) { $optionValueFields = CRM_Core_OptionValue::getFields(); } foreach ($optionValueFields as $field => $params) { $fields[$field]['title'] = $params['title']; } $diffs = self::findDifferences($main, $other); $rows = $elements = $relTableElements = $migrationInfo = array(); $genders = CRM_Core_PseudoConstant::get('CRM_Contact_DAO_Contact', 'gender_id'); foreach ($diffs['contact'] as $field) { if ($field == 'contact_sub_type') { // CRM-15681 don't display sub-types in UI continue; } foreach (array('main', 'other') as $moniker) { $contact =& ${$moniker}; $value = CRM_Utils_Array::value($field, $contact); if (isset($specialValues[$moniker][$field]) && is_string($specialValues[$moniker][$field])) { $value = CRM_Core_DAO::VALUE_SEPARATOR . trim($specialValues[$moniker][$field], CRM_Core_DAO::VALUE_SEPARATOR) . CRM_Core_DAO::VALUE_SEPARATOR; } $label = isset($specialValues[$moniker]["{$field}_display"]) ? $specialValues[$moniker]["{$field}_display"] : $value; if (!empty($fields[$field]['type']) && $fields[$field]['type'] == CRM_Utils_Type::T_DATE) { if ($value) { $value = str_replace('-', '', $value); $label = CRM_Utils_Date::customFormat($label); } else { $value = "null"; } } elseif (!empty($fields[$field]['type']) && $fields[$field]['type'] == CRM_Utils_Type::T_BOOLEAN) { if ($label === '0') { $label = ts('[ ]'); } if ($label === '1') { $label = ts('[x]'); } } elseif ($field == 'individual_prefix' || $field == 'prefix_id') { $label = CRM_Utils_Array::value('individual_prefix', $contact); $value = CRM_Utils_Array::value('prefix_id', $contact); $field = 'prefix_id'; } elseif ($field == 'individual_suffix' || $field == 'suffix_id') { $label = CRM_Utils_Array::value('individual_suffix', $contact); $value = CRM_Utils_Array::value('suffix_id', $contact); $field = 'suffix_id'; } elseif ($field == 'gender_id' && !empty($value)) { $label = $genders[$value]; } elseif ($field == 'current_employer_id' && !empty($value)) { $label = "{$value} (" . CRM_Contact_BAO_Contact::displayName($value) . ")"; } $rows["move_{$field}"][$moniker] = $label; if ($moniker == 'other') { //CRM-14334 if ($value === NULL || $value == '') { $value = 'null'; } if ($value === 0 or $value === '0') { $value = $qfZeroBug; } if (is_array($value) && empty($value[1])) { $value[1] = NULL; } $elements[] = array('advcheckbox', "move_{$field}", NULL, NULL, NULL, $value); $migrationInfo["move_{$field}"] = $value; } } $rows["move_{$field}"]['title'] = $fields[$field]['title']; } // handle location blocks. $locationBlocks = array('email', 'phone', 'address'); $locations = array(); foreach ($locationBlocks as $block) { foreach (array('main' => $mainId, 'other' => $otherId) as $moniker => $cid) { $cnt = 1; $values = civicrm_api($block, 'get', array('contact_id' => $cid, 'version' => 3)); $count = $values['count']; if ($count) { if ($count > $cnt) { foreach ($values['values'] as $value) { if ($block == 'address') { CRM_Core_BAO_Address::fixAddress($value); $display = CRM_Utils_Address::format($value); $locations[$moniker][$block][$cnt] = $value; $locations[$moniker][$block][$cnt]['display'] = $display; } else { $locations[$moniker][$block][$cnt] = $value; } $cnt++; } } else { $id = $values['id']; if ($block == 'address') { CRM_Core_BAO_Address::fixAddress($values['values'][$id]); $display = CRM_Utils_Address::format($values['values'][$id]); $locations[$moniker][$block][$cnt] = $values['values'][$id]; $locations[$moniker][$block][$cnt]['display'] = $display; } else { $locations[$moniker][$block][$cnt] = $values['values'][$id]; } } } } } $allLocationTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Address', 'location_type_id'); $mainLocBlock = $locBlockIds = array(); $locBlockIds['main'] = $locBlockIds['other'] = array(); foreach (array('Email', 'Phone', 'IM', 'OpenID', 'Address') as $block) { $name = strtolower($block); foreach (array('main', 'other') as $moniker) { $locIndex = CRM_Utils_Array::value($moniker, $locations); $blockValue = CRM_Utils_Array::value($name, $locIndex, array()); if (empty($blockValue)) { $locValue[$moniker][$name] = 0; $locLabel[$moniker][$name] = $locTypes[$moniker][$name] = array(); } else { $locValue[$moniker][$name] = TRUE; foreach ($blockValue as $count => $blkValues) { $fldName = $name; $locTypeId = $blkValues['location_type_id']; if ($name == 'im') { $fldName = 'name'; } if ($name == 'address') { $fldName = 'display'; } $locLabel[$moniker][$name][$count] = CRM_Utils_Array::value($fldName, $blkValues); $locTypes[$moniker][$name][$count] = $locTypeId; if ($moniker == 'main' && in_array($name, $locationBlocks)) { $mainLocBlock["main_{$name}{$locTypeId}"] = CRM_Utils_Array::value($fldName, $blkValues); $locBlockIds['main'][$name][$locTypeId] = $blkValues['id']; } else { $locBlockIds[$moniker][$name][$count] = $blkValues['id']; } } } } if ($locValue['other'][$name] != 0) { foreach ($locLabel['other'][$name] as $count => $value) { $locTypeId = $locTypes['other'][$name][$count]; $rows["move_location_{$name}_{$count}"]['other'] = $value; $rows["move_location_{$name}_{$count}"]['main'] = CRM_Utils_Array::value($count, $locLabel['main'][$name]); $rows["move_location_{$name}_{$count}"]['title'] = ts('%1:%2:%3', array(1 => $block, 2 => $count, 3 => $allLocationTypes[$locTypeId])); $elements[] = array('advcheckbox', "move_location_{$name}_{$count}"); $migrationInfo["move_location_{$name}_{$count}"] = 1; // make sure default location type is always on top $mainLocTypeId = CRM_Utils_Array::value($count, $locTypes['main'][$name], $locTypeId); $locTypeValues = $allLocationTypes; $defaultLocType = array($mainLocTypeId => $locTypeValues[$mainLocTypeId]); unset($locTypeValues[$mainLocTypeId]); // keep 1-1 mapping for address - location type. $js = NULL; if (in_array($name, $locationBlocks) && !empty($mainLocBlock)) { $js = array('onChange' => "mergeBlock('{$name}', this, {$count} );"); } $elements[] = array('select', "location[{$name}][{$count}][locTypeId]", NULL, $defaultLocType + $locTypeValues, $js); // keep location-type-id same as that of other-contact $migrationInfo['location'][$name][$count]['locTypeId'] = $locTypeId; if ($name != 'address') { $elements[] = array('advcheckbox', "location[{$name}][{$count}][operation]", NULL, ts('add new')); // always use add operation $migrationInfo['location'][$name][$count]['operation'] = 1; } } } } // add the related tables and unset the ones that don't sport any of the duplicate contact's info $config = CRM_Core_Config::singleton(); $mainUfId = CRM_Core_BAO_UFMatch::getUFId($mainId); $mainUser = NULL; if ($mainUfId) { // d6 compatible if ($config->userSystem->is_drupal == '1' && function_exists($mainUser)) { $mainUser = user_load($mainUfId); } elseif ($config->userFramework == 'Joomla') { $mainUser = JFactory::getUser($mainUfId); } } $otherUfId = CRM_Core_BAO_UFMatch::getUFId($otherId); $otherUser = NULL; if ($otherUfId) { // d6 compatible if ($config->userSystem->is_drupal == '1' && function_exists($mainUser)) { $otherUser = user_load($otherUfId); } elseif ($config->userFramework == 'Joomla') { $otherUser = JFactory::getUser($otherUfId); } } $relTables = CRM_Dedupe_Merger::relTables(); $activeRelTables = CRM_Dedupe_Merger::getActiveRelTables($otherId); $activeMainRelTables = CRM_Dedupe_Merger::getActiveRelTables($mainId); foreach ($relTables as $name => $null) { if (!in_array($name, $activeRelTables) && !($name == 'rel_table_users' && in_array($name, $activeMainRelTables))) { unset($relTables[$name]); continue; } $relTableElements[] = array('checkbox', "move_{$name}"); $migrationInfo["move_{$name}"] = 1; $relTables[$name]['main_url'] = str_replace('$cid', $mainId, $relTables[$name]['url']); $relTables[$name]['other_url'] = str_replace('$cid', $otherId, $relTables[$name]['url']); if ($name == 'rel_table_users') { $relTables[$name]['main_url'] = str_replace('%ufid', $mainUfId, $relTables[$name]['url']); $relTables[$name]['other_url'] = str_replace('%ufid', $otherUfId, $relTables[$name]['url']); $find = array('$ufid', '$ufname'); if ($mainUser) { $replace = array($mainUfId, $mainUser->name); $relTables[$name]['main_title'] = str_replace($find, $replace, $relTables[$name]['title']); } if ($otherUser) { $replace = array($otherUfId, $otherUser->name); $relTables[$name]['other_title'] = str_replace($find, $replace, $relTables[$name]['title']); } } if ($name == 'rel_table_memberships') { $elements[] = array('checkbox', "operation[move_{$name}][add]", NULL, ts('add new')); $migrationInfo["operation"]["move_{$name}"]['add'] = 1; } } foreach ($relTables as $name => $null) { $relTables["move_{$name}"] = $relTables[$name]; unset($relTables[$name]); } // handle custom fields $mainTree = CRM_Core_BAO_CustomGroup::getTree($main['contact_type'], CRM_Core_DAO::$_nullObject, $mainId, -1, CRM_Utils_Array::value('contact_sub_type', $main)); $otherTree = CRM_Core_BAO_CustomGroup::getTree($main['contact_type'], CRM_Core_DAO::$_nullObject, $otherId, -1, CRM_Utils_Array::value('contact_sub_type', $other)); CRM_Core_DAO::freeResult(); foreach ($otherTree as $gid => $group) { $foundField = FALSE; if (!isset($group['fields'])) { continue; } foreach ($group['fields'] as $fid => $field) { if (in_array($fid, $diffs['custom'])) { if (!$foundField) { $rows["custom_group_{$gid}"]['title'] = $group['title']; $foundField = TRUE; } if (!empty($mainTree[$gid]['fields'][$fid]['customValue'])) { foreach ($mainTree[$gid]['fields'][$fid]['customValue'] as $valueId => $values) { $rows["move_custom_{$fid}"]['main'] = CRM_Core_BAO_CustomGroup::formatCustomValues($values, $field, TRUE); } } $value = "null"; if (!empty($otherTree[$gid]['fields'][$fid]['customValue'])) { foreach ($otherTree[$gid]['fields'][$fid]['customValue'] as $valueId => $values) { $rows["move_custom_{$fid}"]['other'] = CRM_Core_BAO_CustomGroup::formatCustomValues($values, $field, TRUE); if ($values['data'] === 0 || $values['data'] === '0') { $values['data'] = $qfZeroBug; } $value = $values['data'] ? $values['data'] : $value; } } $rows["move_custom_{$fid}"]['title'] = $field['label']; $elements[] = array('advcheckbox', "move_custom_{$fid}", NULL, NULL, NULL, $value); $migrationInfo["move_custom_{$fid}"] = $value; } } } $result = array('rows' => $rows, 'elements' => $elements, 'rel_table_elements' => $relTableElements, 'main_loc_block' => $mainLocBlock, 'rel_tables' => $relTables, 'main_details' => $main, 'other_details' => $other, 'migration_info' => $migrationInfo); $result['main_details']['loc_block_ids'] = $locBlockIds['main']; $result['other_details']['loc_block_ids'] = $locBlockIds['other']; return $result; }
public static function csv() { $csvFile = '/home/deepak/Desktop/crm-4247.csv'; $delimiter = ";"; $row = 1; $handle = fopen($csvFile, "r"); if (!$handle) { CRM_Core_Error::fatal("Can't locate csv file."); } require_once "CRM/Contribute/BAO/Contribution/Utils.php"; while (($data = fgetcsv($handle, 1000, $delimiter)) !== FALSE) { if ($row !== 1) { $data['header'] = $header; $params = self::formatAPIParams($data, self::$_csvParamsMapper, 'csv'); if (self::processAPIContribution($params)) { CRM_Core_Error::debug_log_message("Processed - line {$row} of csv file .. {$params['email']}, {$params['transaction']['total_amount']}, {$params['transaction']['trxn_id']} ..<p>", TRUE); } else { CRM_Core_Error::debug_log_message("Skipped - line {$row} of csv file .. {$params['email']}, {$params['transaction']['total_amount']}, {$params['transaction']['trxn_id']} ..<p>", TRUE); } // clean up memory from dao's CRM_Core_DAO::freeResult(); } else { // we assuming - first row is always the header line $header = $data; CRM_Core_Error::debug_log_message("Considering first row ( line {$row} ) as HEADER ..<p>", TRUE); if (empty($header)) { CRM_Core_Error::fatal("Header is empty."); } } $row++; } fclose($handle); }
/** * A function to build an array of information required by merge function and the merge UI. * * @param int $mainId * Main contact with whom merge has to happen. * @param int $otherId * Duplicate contact which would be deleted after merge operation. * * @return array|bool|int * 'main_loc_block' => Stores all location blocks associated with the 'main' contact */ public static function getRowsElementsAndInfo($mainId, $otherId) { $qfZeroBug = 'e8cddb72-a257-11dc-b9cc-0016d3330ee9'; // Fetch contacts foreach (array('main' => $mainId, 'other' => $otherId) as $moniker => $cid) { $params = array('contact_id' => $cid, 'version' => 3, 'return' => array_merge(array('display_name'), self::getContactFields())); $result = civicrm_api('contact', 'get', $params); if (empty($result['values'][$cid]['contact_type'])) { return FALSE; } ${$moniker} = $result['values'][$cid]; } $fields = CRM_Contact_DAO_Contact::fields(); // FIXME: there must be a better way foreach (array('main', 'other') as $moniker) { $contact =& ${$moniker}; $preferred_communication_method = CRM_Utils_array::value('preferred_communication_method', $contact); $value = empty($preferred_communication_method) ? array() : $preferred_communication_method; $specialValues[$moniker] = array('preferred_communication_method' => $value, 'communication_style_id' => $value); if (!empty($contact['preferred_communication_method'])) { // api 3 returns pref_comm_method as an array, which breaks the lookup; so we reconstruct $prefCommList = is_array($specialValues[$moniker]['preferred_communication_method']) ? implode(CRM_Core_DAO::VALUE_SEPARATOR, $specialValues[$moniker]['preferred_communication_method']) : $specialValues[$moniker]['preferred_communication_method']; $specialValues[$moniker]['preferred_communication_method'] = CRM_Core_DAO::VALUE_SEPARATOR . $prefCommList . CRM_Core_DAO::VALUE_SEPARATOR; } $names = array('preferred_communication_method' => array('newName' => 'preferred_communication_method_display', 'groupName' => 'preferred_communication_method')); CRM_Core_OptionGroup::lookupValues($specialValues[$moniker], $names); if (!empty($contact['communication_style'])) { $specialValues[$moniker]['communication_style_id_display'] = $contact['communication_style']; } } static $optionValueFields = array(); if (empty($optionValueFields)) { $optionValueFields = CRM_Core_OptionValue::getFields(); } foreach ($optionValueFields as $field => $params) { $fields[$field]['title'] = $params['title']; } $compareFields = self::retrieveFields($main, $other); $rows = $elements = $relTableElements = $migrationInfo = array(); foreach ($compareFields['contact'] as $field) { if ($field == 'contact_sub_type') { // CRM-15681 don't display sub-types in UI continue; } foreach (array('main', 'other') as $moniker) { $contact =& ${$moniker}; $value = CRM_Utils_Array::value($field, $contact); if (isset($specialValues[$moniker][$field]) && is_string($specialValues[$moniker][$field])) { $value = CRM_Core_DAO::VALUE_SEPARATOR . trim($specialValues[$moniker][$field], CRM_Core_DAO::VALUE_SEPARATOR) . CRM_Core_DAO::VALUE_SEPARATOR; } $label = isset($specialValues[$moniker]["{$field}_display"]) ? $specialValues[$moniker]["{$field}_display"] : $value; if (!empty($fields[$field]['type']) && $fields[$field]['type'] == CRM_Utils_Type::T_DATE) { if ($value) { $value = str_replace('-', '', $value); $label = CRM_Utils_Date::customFormat($label); } else { $value = "null"; } } elseif (!empty($fields[$field]['type']) && $fields[$field]['type'] == CRM_Utils_Type::T_BOOLEAN) { if ($label === '0') { $label = ts('[ ]'); } if ($label === '1') { $label = ts('[x]'); } } elseif ($field == 'individual_prefix' || $field == 'prefix_id') { $label = CRM_Utils_Array::value('individual_prefix', $contact); $value = CRM_Utils_Array::value('prefix_id', $contact); $field = 'prefix_id'; } elseif ($field == 'individual_suffix' || $field == 'suffix_id') { $label = CRM_Utils_Array::value('individual_suffix', $contact); $value = CRM_Utils_Array::value('suffix_id', $contact); $field = 'suffix_id'; } elseif ($field == 'gender_id' && !empty($value)) { $genderOptions = civicrm_api3('contact', 'getoptions', array('field' => 'gender_id')); $label = $genderOptions['values'][$value]; } elseif ($field == 'current_employer_id' && !empty($value)) { $label = "{$value} (" . CRM_Contact_BAO_Contact::displayName($value) . ")"; } $rows["move_{$field}"][$moniker] = $label; if ($moniker == 'other') { //CRM-14334 if ($value === NULL || $value == '') { $value = 'null'; } if ($value === 0 or $value === '0') { $value = $qfZeroBug; } if (is_array($value) && empty($value[1])) { $value[1] = NULL; } // Display a checkbox to migrate, only if the values are different if ($value != $main[$field]) { $elements[] = array('advcheckbox', "move_{$field}", NULL, NULL, NULL, $value); } $migrationInfo["move_{$field}"] = $value; } } $rows["move_{$field}"]['title'] = $fields[$field]['title']; } // Handle location blocks. // @todo OpenID not in API yet, so is not supported here. // Set up useful information about the location blocks $locationBlocks = self::getLocationBlockInfo(); $locations = array('main' => array(), 'other' => array()); $mainLocBlock = array(); // @todo This could probably be defined and used earlier $mergeTargets = array('main' => $mainId, 'other' => $otherId); foreach ($locationBlocks as $blockName => $blockInfo) { // Collect existing fields from both 'main' and 'other' contacts first // This allows us to match up location/types when building the table rows foreach ($mergeTargets as $moniker => $cid) { $cnt = 1; $searchParams = array('version' => 3, 'contact_id' => $cid, 'options' => array('sort' => $blockInfo['sortString'])); $values = civicrm_api($blockName, 'get', $searchParams); if ($values['count']) { $cnt = 0; foreach ($values['values'] as $index => $value) { $locations[$moniker][$blockName][$cnt] = $value; // Fix address display $display = ''; if ($blockName == 'address') { CRM_Core_BAO_Address::fixAddress($value); $display = CRM_Utils_Address::format($value); $locations[$moniker][$blockName][$cnt]['display'] = $display; } // Add any 'main' contact block values to an array for the JS // @todo The JS should just access the main_details to find this info? if ($moniker == 'main') { if ($blockInfo['hasType']) { // Handle websites, no location type ID // @todo Remove the need for this specific 'if' if ($blockName == 'website') { $value['location_type_id'] = 0; } $mainLocBlock["main_" . $blockName . "_" . $value['location_type_id'] . "_" . $value[$blockInfo['hasType']]]['display'] = $value[$blockInfo['displayField']]; $mainLocBlock["main_" . $blockName . "_" . $value['location_type_id'] . "_" . $value[$blockInfo['hasType']]]['id'] = $value['id']; } else { // Get the correct display value for addresses // @todo Remove the need for this if... if ($blockName == 'address') { $mainLocBlock["main_" . $blockName . "_" . $value['location_type_id']]['display'] = $display; $mainLocBlock["main_" . $blockName . "_" . $value['location_type_id']]['id'] = $value['id']; } else { $mainLocBlock["main_" . $blockName . "_" . $value['location_type_id']]['display'] = $value[$blockInfo['displayField']]; $mainLocBlock["main_" . $blockName . "_" . $value['location_type_id']]['id'] = $value['id']; } } } $cnt++; } } } // Now, build the table rows appropriately, based off the information on // the 'other' contact if (!empty($locations['other']) && !empty($locations['other'][$blockName])) { foreach ($locations['other'][$blockName] as $count => $value) { $displayValue = $value[$blockInfo['displayField']]; // Add this value to the table rows $rows["move_location_{$blockName}_{$count}"]['other'] = $displayValue; // CRM-17556 Only display 'main' contact value if it's the same location + type // Look it up from main values... $lookupLocation = FALSE; if ($blockInfo['hasLocation']) { $lookupLocation = $value['location_type_id']; } $lookupType = FALSE; if ($blockInfo['hasType']) { $lookupType = $value[$blockInfo['hasType']]; } // Hold ID of main contact's matching block $mainContactBlockId = 0; if (!empty($locations['main'][$blockName])) { foreach ($locations['main'][$blockName] as $mainValueCheck) { // No location/type, or matching location and type if ((empty($lookupLocation) || $lookupLocation == $mainValueCheck['location_type_id']) && (empty($lookupType) || $lookupType == $mainValueCheck[$blockInfo['hasType']])) { // Set this value as the default against the 'other' contact value $rows["move_location_{$blockName}_{$count}"]['main'] = $mainValueCheck[$blockInfo['displayField']]; $mainContactBlockId = $mainValueCheck['id']; break; } } } // Add checkbox to migrate data from 'other' to 'main' $elements[] = array('advcheckbox', "move_location_{$blockName}_{$count}"); // Flag up this field to skipMerge function (@todo: do we need to?) $migrationInfo["move_location_{$blockName}_{$count}"] = 1; // Add a hidden field to store the ID of the target main contact block $elements[] = array('hidden', "location[{$blockName}][{$count}][mainContactBlockId]", $mainContactBlockId); // Setup variables $thisTypeId = FALSE; $thisLocId = FALSE; // Provide a select drop-down for the location's location type // eg: Home, Work... $js = NULL; if ($blockInfo['hasLocation']) { // Load the location options for this entity $locationOptions = civicrm_api3($blockName, 'getoptions', array('field' => 'location_type_id')); // JS lookup 'main' contact's location (if there are any) if (!empty($locations['main'][$blockName])) { $js = array('onChange' => "mergeBlock('{$blockName}', this, {$count}, 'locTypeId' );"); } $thisLocId = $value['location_type_id']; // Put this field's location type at the top of the list $tmpIdList = $locationOptions['values']; $defaultLocId = array($thisLocId => $tmpIdList[$thisLocId]); unset($tmpIdList[$thisLocId]); // Add the element $elements[] = array('select', "location[{$blockName}][{$count}][locTypeId]", NULL, $defaultLocId + $tmpIdList, $js); // Add the relevant information to the $migrationInfo // Keep location-type-id same as that of other-contact // @todo Check this logic out $migrationInfo['location_blocks'][$blockName][$count]['locTypeId'] = $thisLocId; if ($blockName != 'address') { $elements[] = array('advcheckbox', "location[{$blockName}][{$count}][operation]", NULL, ts('add new')); // always use add operation $migrationInfo['location_blocks'][$blockName][$count]['operation'] = 1; } } // Provide a select drop-down for the location's type/provider // eg websites: Google+, Facebook... $js = NULL; if ($blockInfo['hasType']) { // Load the type options for this entity $typeOptions = civicrm_api3($blockName, 'getoptions', array('field' => $blockInfo['hasType'])); // CRM-17556 Set up JS lookup of 'main' contact's value by type if (!empty($locations['main'][$blockName])) { $js = array('onChange' => "mergeBlock('{$blockName}', this, {$count}, 'typeTypeId' );"); } $thisTypeId = $value[$blockInfo['hasType']]; // Put this field's location type at the top of the list $tmpIdList = $typeOptions['values']; $defaultTypeId = array($thisTypeId => $tmpIdList[$thisTypeId]); unset($tmpIdList[$thisTypeId]); // Add the element $elements[] = array('select', "location[{$blockName}][{$count}][typeTypeId]", NULL, $defaultTypeId + $tmpIdList, $js); // Add the information to the migrationInfo (@todo Why?) $migrationInfo['location_blocks'][$blockName][$count]['typeTypeId'] = $thisTypeId; } // Set the label for this row $rowTitle = $blockInfo['label'] . ' ' . ($count + 1); if (!empty($thisLocId)) { $rowTitle .= ' (' . $locationOptions['values'][$thisLocId] . ')'; } if (!empty($thisTypeId)) { $rowTitle .= ' (' . $typeOptions['values'][$thisTypeId] . ')'; } $rows["move_location_{$blockName}_{$count}"]['title'] = $rowTitle; } // End loop through 'other' locations of this type } // End if 'other' location for this type exists } // End loop through each location block entity // add the related tables and unset the ones that don't sport any of the duplicate contact's info $config = CRM_Core_Config::singleton(); $mainUfId = CRM_Core_BAO_UFMatch::getUFId($mainId); $mainUser = NULL; if ($mainUfId) { // d6 compatible if ($config->userSystem->is_drupal == '1' && function_exists($mainUser)) { $mainUser = user_load($mainUfId); } elseif ($config->userFramework == 'Joomla') { $mainUser = JFactory::getUser($mainUfId); } } $otherUfId = CRM_Core_BAO_UFMatch::getUFId($otherId); $otherUser = NULL; if ($otherUfId) { // d6 compatible if ($config->userSystem->is_drupal == '1' && function_exists($mainUser)) { $otherUser = user_load($otherUfId); } elseif ($config->userFramework == 'Joomla') { $otherUser = JFactory::getUser($otherUfId); } } $relTables = CRM_Dedupe_Merger::relTables(); $activeRelTables = CRM_Dedupe_Merger::getActiveRelTables($otherId); $activeMainRelTables = CRM_Dedupe_Merger::getActiveRelTables($mainId); foreach ($relTables as $name => $null) { if (!in_array($name, $activeRelTables) && !($name == 'rel_table_users' && in_array($name, $activeMainRelTables))) { unset($relTables[$name]); continue; } $relTableElements[] = array('checkbox', "move_{$name}"); $migrationInfo["move_{$name}"] = 1; $relTables[$name]['main_url'] = str_replace('$cid', $mainId, $relTables[$name]['url']); $relTables[$name]['other_url'] = str_replace('$cid', $otherId, $relTables[$name]['url']); if ($name == 'rel_table_users') { $relTables[$name]['main_url'] = str_replace('%ufid', $mainUfId, $relTables[$name]['url']); $relTables[$name]['other_url'] = str_replace('%ufid', $otherUfId, $relTables[$name]['url']); $find = array('$ufid', '$ufname'); if ($mainUser) { $replace = array($mainUfId, $mainUser->name); $relTables[$name]['main_title'] = str_replace($find, $replace, $relTables[$name]['title']); } if ($otherUser) { $replace = array($otherUfId, $otherUser->name); $relTables[$name]['other_title'] = str_replace($find, $replace, $relTables[$name]['title']); } } if ($name == 'rel_table_memberships') { $elements[] = array('checkbox', "operation[move_{$name}][add]", NULL, ts('add new')); $migrationInfo["operation"]["move_{$name}"]['add'] = 1; } } foreach ($relTables as $name => $null) { $relTables["move_{$name}"] = $relTables[$name]; unset($relTables[$name]); } // handle custom fields $mainTree = CRM_Core_BAO_CustomGroup::getTree($main['contact_type'], CRM_Core_DAO::$_nullObject, $mainId, -1, CRM_Utils_Array::value('contact_sub_type', $main)); $otherTree = CRM_Core_BAO_CustomGroup::getTree($main['contact_type'], CRM_Core_DAO::$_nullObject, $otherId, -1, CRM_Utils_Array::value('contact_sub_type', $other)); CRM_Core_DAO::freeResult(); foreach ($otherTree as $gid => $group) { $foundField = FALSE; if (!isset($group['fields'])) { continue; } foreach ($group['fields'] as $fid => $field) { if (in_array($fid, $compareFields['custom'])) { if (!$foundField) { $rows["custom_group_{$gid}"]['title'] = $group['title']; $foundField = TRUE; } if (!empty($mainTree[$gid]['fields'][$fid]['customValue'])) { foreach ($mainTree[$gid]['fields'][$fid]['customValue'] as $valueId => $values) { $rows["move_custom_{$fid}"]['main'] = CRM_Core_BAO_CustomField::displayValue($values['data'], $fid); } } $value = "null"; if (!empty($otherTree[$gid]['fields'][$fid]['customValue'])) { foreach ($otherTree[$gid]['fields'][$fid]['customValue'] as $valueId => $values) { $rows["move_custom_{$fid}"]['other'] = CRM_Core_BAO_CustomField::displayValue($values['data'], $fid); if ($values['data'] === 0 || $values['data'] === '0') { $values['data'] = $qfZeroBug; } $value = $values['data'] ? $values['data'] : $value; } } $rows["move_custom_{$fid}"]['title'] = $field['label']; $elements[] = array('advcheckbox', "move_custom_{$fid}", NULL, NULL, NULL, $value); $migrationInfo["move_custom_{$fid}"] = $value; } } } $result = array('rows' => $rows, 'elements' => $elements, 'rel_table_elements' => $relTableElements, 'main_loc_block' => $mainLocBlock, 'rel_tables' => $relTables, 'main_details' => $main, 'other_details' => $other, 'migration_info' => $migrationInfo); $result['main_details']['location_blocks'] = $locations['main']; $result['other_details']['location_blocks'] = $locations['other']; return $result; }
function run($tableName, &$mapper, $mode = self::MODE_PREVIEW, $contactType = self::CONTACT_INDIVIDUAL, $primaryKeyName = '_id', $statusFieldName = '_status', $onDuplicate = self::DUPLICATE_SKIP, $statusID = NULL, $totalRowCount = NULL, $doGeocodeAddress = FALSE, $timeout = CRM_Contact_Import_Parser::DEFAULT_TIMEOUT, $contactSubType = NULL, $dedupeRuleGroupID = NULL) { // TODO: Make the timeout actually work $this->_onDuplicate = $onDuplicate; $this->_dedupeRuleGroupID = $dedupeRuleGroupID; switch ($contactType) { case CRM_Import_Parser::CONTACT_INDIVIDUAL: $this->_contactType = 'Individual'; break; case CRM_Import_Parser::CONTACT_HOUSEHOLD: $this->_contactType = 'Household'; break; case CRM_Import_Parser::CONTACT_ORGANIZATION: $this->_contactType = 'Organization'; } $this->_contactSubType = $contactSubType; $this->init(); $this->_rowCount = $this->_warningCount = 0; $this->_invalidRowCount = $this->_validCount = 0; $this->_totalCount = $this->_conflictCount = 0; $this->_errors = array(); $this->_warnings = array(); $this->_conflicts = array(); $this->_unparsedAddresses = array(); $status = ''; $this->_tableName = $tableName; $this->_primaryKeyName = $primaryKeyName; $this->_statusFieldName = $statusFieldName; if ($mode == self::MODE_MAPFIELD) { $this->_rows = array(); } else { $this->_activeFieldCount = count($this->_activeFields); } if ($mode == self::MODE_IMPORT) { //get the key of email field foreach ($mapper as $key => $value) { if (strtolower($value) == 'email') { $emailKey = $key; break; } } } if ($statusID) { $skip = 50; // $skip = 1; $config = CRM_Core_Config::singleton(); $statusFile = "{$config->uploadDir}status_{$statusID}.txt"; $status = "<div class='description'> " . ts('No processing status reported yet.') . "</div>"; //do not force the browser to display the save dialog, CRM-7640 $contents = json_encode(array(0, $status)); file_put_contents($statusFile, $contents); $startTimestamp = $currTimestamp = $prevTimestamp = time(); } // get the contents of the temp. import table $query = "SELECT * FROM {$tableName}"; if ($mode == self::MODE_IMPORT) { $query .= " WHERE {$statusFieldName} = 'NEW'"; } $dao = new CRM_Core_DAO(); $db = $dao->getDatabaseConnection(); $result = $db->query($query); while ($values = $result->fetchRow(DB_FETCHMODE_ORDERED)) { $this->_rowCount++; /* trim whitespace around the values */ $empty = TRUE; foreach ($values as $k => $v) { $values[$k] = trim($v, " \t\r\n"); } if (CRM_Utils_System::isNull($values)) { continue; } $this->_totalCount++; if ($mode == self::MODE_MAPFIELD) { $returnCode = $this->mapField($values); } elseif ($mode == self::MODE_PREVIEW) { $returnCode = $this->preview($values); } elseif ($mode == self::MODE_SUMMARY) { $returnCode = $this->summary($values); } elseif ($mode == self::MODE_IMPORT) { //print "Running parser in import mode<br/>\n"; $returnCode = $this->import($onDuplicate, $values, $doGeocodeAddress); if ($statusID && $this->_rowCount % $skip == 0) { $currTimestamp = time(); $totalTime = $currTimestamp - $startTimestamp; $time = $currTimestamp - $prevTimestamp; $recordsLeft = $totalRowCount - $this->_rowCount; if ($recordsLeft < 0) { $recordsLeft = 0; } $estimatedTime = $recordsLeft / $skip * $time; $estMinutes = floor($estimatedTime / 60); $timeFormatted = ''; if ($estMinutes > 1) { $timeFormatted = $estMinutes . ' ' . ts('minutes') . ' '; $estimatedTime = $estimatedTime - $estMinutes * 60; } $timeFormatted .= round($estimatedTime) . ' ' . ts('seconds'); $processedPercent = (int) ($this->_rowCount * 100 / $totalRowCount); $statusMsg = ts('%1 of %2 records - %3 remaining', array(1 => $this->_rowCount, 2 => $totalRowCount, 3 => $timeFormatted)); $status = "\n<div class=\"description\">\n <strong>{$statusMsg}</strong>\n</div>\n"; $contents = json_encode(array($processedPercent, $status)); file_put_contents($statusFile, $contents); $prevTimestamp = $currTimestamp; } // sleep(1); } else { $returnCode = self::ERROR; } // note that a line could be valid but still produce a warning if ($returnCode & self::VALID) { $this->_validCount++; if ($mode == self::MODE_MAPFIELD) { $this->_rows[] = $values; $this->_activeFieldCount = max($this->_activeFieldCount, count($values)); } } if ($returnCode & self::WARNING) { $this->_warningCount++; if ($this->_warningCount < $this->_maxWarningCount) { $this->_warningCount[] = $line; } } if ($returnCode & self::ERROR) { $this->_invalidRowCount++; if ($this->_invalidRowCount < $this->_maxErrorCount) { array_unshift($values, $this->_rowCount); $this->_errors[] = $values; } } if ($returnCode & self::CONFLICT) { $this->_conflictCount++; array_unshift($values, $this->_rowCount); $this->_conflicts[] = $values; } if ($returnCode & self::NO_MATCH) { $this->_unMatchCount++; array_unshift($values, $this->_rowCount); $this->_unMatch[] = $values; } if ($returnCode & self::DUPLICATE) { if ($returnCode & self::MULTIPLE_DUPE) { /* TODO: multi-dupes should be counted apart from singles * on non-skip action */ } $this->_duplicateCount++; array_unshift($values, $this->_rowCount); $this->_duplicates[] = $values; if ($onDuplicate != self::DUPLICATE_SKIP) { $this->_validCount++; } } if ($returnCode & self::UNPARSED_ADDRESS_WARNING) { $this->_unparsedAddressCount++; array_unshift($values, $this->_rowCount); $this->_unparsedAddresses[] = $values; } // we give the derived class a way of aborting the process // note that the return code could be multiple code or'ed together if ($returnCode & self::STOP) { break; } // if we are done processing the maxNumber of lines, break if ($this->_maxLinesToProcess > 0 && $this->_validCount >= $this->_maxLinesToProcess) { break; } // clean up memory from dao's CRM_Core_DAO::freeResult(); // see if we've hit our timeout yet /* if ( $the_thing_with_the_stuff ) { do_something( ); } */ } if ($mode == self::MODE_PREVIEW || $mode == self::MODE_IMPORT) { $customHeaders = $mapper; $customfields = CRM_Core_BAO_CustomField::getFields($this->_contactType); foreach ($customHeaders as $key => $value) { if ($id = CRM_Core_BAO_CustomField::getKeyID($value)) { $customHeaders[$key] = $customfields[$id][0]; } } if ($this->_invalidRowCount) { // removed view url for invlaid contacts $headers = array_merge(array(ts('Line Number'), ts('Reason')), $customHeaders); $this->_errorFileName = self::errorFileName(self::ERROR); self::exportCSV($this->_errorFileName, $headers, $this->_errors); } if ($this->_conflictCount) { $headers = array_merge(array(ts('Line Number'), ts('Reason')), $customHeaders); $this->_conflictFileName = self::errorFileName(self::CONFLICT); self::exportCSV($this->_conflictFileName, $headers, $this->_conflicts); } if ($this->_duplicateCount) { $headers = array_merge(array(ts('Line Number'), ts('View Contact URL')), $customHeaders); $this->_duplicateFileName = self::errorFileName(self::DUPLICATE); self::exportCSV($this->_duplicateFileName, $headers, $this->_duplicates); } if ($this->_unMatchCount) { $headers = array_merge(array(ts('Line Number'), ts('Reason')), $customHeaders); $this->_misMatchFilemName = self::errorFileName(self::NO_MATCH); self::exportCSV($this->_misMatchFilemName, $headers, $this->_unMatch); } if ($this->_unparsedAddressCount) { $headers = array_merge(array(ts('Line Number'), ts('Contact Edit URL')), $customHeaders); $this->_errorFileName = self::errorFileName(self::UNPARSED_ADDRESS_WARNING); self::exportCSV($this->_errorFileName, $headers, $this->_unparsedAddresses); } } //echo "$this->_totalCount,$this->_invalidRowCount,$this->_conflictCount,$this->_duplicateCount"; return $this->fini(); }
/** * This function acts as a listener to dao->update whenever there is an update, * and propagates any changes to all related entities present in recurring entity table * * @param object $event * An object of /Civi/Core/DAO/Event/PostUpdate containing dao object that was just updated . * * * @return void */ public static function triggerUpdate($event) { // if DB version is earlier than 4.6 skip any processing static $currentVer = NULL; if (!$currentVer) { $currentVer = CRM_Core_BAO_Domain::version(); } if (version_compare($currentVer, '4.6.alpha1') < 0) { return; } static $processedEntities = array(); $obj =& $event->object; if (empty($obj->id) || empty($obj->__table)) { return FALSE; } $key = "{$obj->__table}_{$obj->id}"; if (array_key_exists($key, $processedEntities)) { // already processed return NULL; } // get related entities $repeatingEntities = self::getEntitiesFor($obj->id, $obj->__table, FALSE, NULL); if (empty($repeatingEntities)) { // return if its not a recurring entity parent return NULL; } // mark being processed $processedEntities[$key] = 1; // to make sure we not copying to source itself unset($repeatingEntities[$key]); foreach ($repeatingEntities as $key => $val) { $entityID = $val['id']; $entityTable = $val['table']; $processedEntities[$key] = 1; if (array_key_exists($entityTable, self::$_tableDAOMapper)) { $daoName = self::$_tableDAOMapper[$entityTable]; $skipData = array(); if (array_key_exists($entityTable, self::$_updateSkipFields)) { $skipFields = self::$_updateSkipFields[$entityTable]; foreach ($skipFields as $sfield) { $skipData[$sfield] = NULL; } } $updateDAO = CRM_Core_DAO::cascadeUpdate($daoName, $obj->id, $entityID, $skipData); CRM_Core_DAO::freeResult(); } else { CRM_Core_Error::fatal("DAO Mapper missing for {$entityTable}."); } } // done with processing. lets unset static var. unset($processedEntities); }
/** * Delete a contact and all its associated records * * @param int $id id of the contact to delete * * @return boolean true if contact deleted, false otherwise * @access public * @static */ function deleteContact($id) { require_once 'CRM/Activity/BAO/Activity.php'; if (!$id) { return false; } // make sure we have edit permission for this contact // before we delete require_once 'CRM/Contact/BAO/Contact/Permission.php'; if (!CRM_Core_Permission::check('delete contacts')) { return false; } // make sure this contact_id does not have any membership types $membershipTypeID = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType', $id, 'id', 'member_of_contact_id'); if ($membershipTypeID) { return false; } $contact =& new CRM_Contact_DAO_Contact(); $contact->id = $id; if (!$contact->find(true)) { return false; } $contactType = $contact->contact_type; // currently we only clear employer cache. // we are not deleting inherited membership if any. if ($contact->contact_type == 'Organization') { require_once 'CRM/Contact/BAO/Contact/Utils.php'; CRM_Contact_BAO_Contact_Utils::clearAllEmployee($id); } require_once 'CRM/Utils/Hook.php'; CRM_Utils_Hook::pre('delete', $contactType, $id, CRM_Core_DAO::$_nullArray); // start a new transaction require_once 'CRM/Core/Transaction.php'; $transaction = new CRM_Core_Transaction(); //delete billing address if exists. require_once 'CRM/Contribute/BAO/Contribution.php'; CRM_Contribute_BAO_Contribution::deleteAddress(null, $id); // delete the log entries since we dont have triggers enabled as yet require_once 'CRM/Core/DAO/Log.php'; $logDAO =& new CRM_Core_DAO_Log(); $logDAO->entity_table = 'civicrm_contact'; $logDAO->entity_id = $id; $logDAO->delete(); $contact->delete(); //delete the contact id from recently view require_once 'CRM/Utils/Recent.php'; CRM_Utils_Recent::delContact($id); // reset the group contact cache for this group require_once 'CRM/Contact/BAO/GroupContactCache.php'; CRM_Contact_BAO_GroupContactCache::remove(); $transaction->commit(); CRM_Utils_Hook::post('delete', $contactType, $contact->id, $contact); // also reset the DB_DO global array so we can reuse the memory // http://issues.civicrm.org/jira/browse/CRM-4387 CRM_Core_DAO::freeResult(); return true; }
/** * Dedupe a pair of contacts. * * @param array $migrationInfo * @param array $resultStats * @param array $deletedContacts * @param string $mode * @param bool $checkPermissions * @param int $mainId * @param int $otherId * @param string $cacheKeyString */ protected static function dedupePair(&$migrationInfo, &$resultStats, &$deletedContacts, $mode, $checkPermissions, $mainId, $otherId, $cacheKeyString) { // go ahead with merge if there is no conflict $conflicts = array(); if (!CRM_Dedupe_Merger::skipMerge($mainId, $otherId, $migrationInfo, $mode, $conflicts)) { CRM_Dedupe_Merger::moveAllBelongings($mainId, $otherId, $migrationInfo, $checkPermissions); $resultStats['merged'][] = array('main_id' => $mainId, 'other_id' => $otherId); $deletedContacts[] = $otherId; } else { $resultStats['skipped'][] = array('main_id' => $mainId, 'other_id' => $otherId); } // store any conflicts if (!empty($conflicts)) { foreach ($conflicts as $key => $dnc) { $conflicts[$key] = "{$migrationInfo['rows'][$key]['title']}: '{$migrationInfo['rows'][$key]['main']}' vs. '{$migrationInfo['rows'][$key]['other']}'"; } CRM_Core_BAO_PrevNextCache::markConflict($mainId, $otherId, $cacheKeyString, $conflicts); } else { // delete entry from PrevNextCache table so we don't consider the pair next time // pair may have been flipped, so make sure we delete using both orders CRM_Core_BAO_PrevNextCache::deletePair($mainId, $otherId, $cacheKeyString, TRUE); } CRM_Core_DAO::freeResult(); }
/** * Delete a contact and all its associated records * * @param int $id id of the contact to delete * @param bool $restore whether to actually restore, not delete * @param bool $skipUndelete whether to force contact delete or not * * @return boolean true if contact deleted, false otherwise * @access public * @static */ static function deleteContact($id, $restore = FALSE, $skipUndelete = FALSE) { if (!$id) { return FALSE; } // make sure we have edit permission for this contact // before we delete if ($skipUndelete && !CRM_Core_Permission::check('delete contacts') || $restore && !CRM_Core_Permission::check('access deleted contacts')) { return FALSE; } // make sure this contact_id does not have any membership types $membershipTypeID = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType', $id, 'id', 'member_of_contact_id'); if ($membershipTypeID) { return FALSE; } $contact = new CRM_Contact_DAO_Contact(); $contact->id = $id; if (!$contact->find(TRUE)) { return FALSE; } $contactType = $contact->contact_type; $action = $restore ? 'restore' : 'delete'; CRM_Utils_Hook::pre($action, $contactType, $id, CRM_Core_DAO::$_nullArray); if ($restore) { self::contactTrashRestore($contact, TRUE); CRM_Utils_Hook::post($action, $contactType, $contact->id, $contact); return TRUE; } // currently we only clear employer cache. // we are not deleting inherited membership if any. if ($contact->contact_type == 'Organization') { CRM_Contact_BAO_Contact_Utils::clearAllEmployee($id); } // start a new transaction $transaction = new CRM_Core_Transaction(); $config = CRM_Core_Config::singleton(); if ($skipUndelete or !$config->contactUndelete) { //delete billing address if exists. CRM_Contribute_BAO_Contribution::deleteAddress(NULL, $id); // delete the log entries since we dont have triggers enabled as yet $logDAO = new CRM_Core_DAO_Log(); $logDAO->entity_table = 'civicrm_contact'; $logDAO->entity_id = $id; $logDAO->delete(); // do activity cleanup, CRM-5604 CRM_Activity_BAO_Activity::cleanupActivity($id); // delete all notes related to contact CRM_Core_BAO_Note::cleanContactNotes($id); $contact->delete(); } else { self::contactTrashRestore($contact); } //delete the contact id from recently view CRM_Utils_Recent::delContact($id); // reset the group contact cache for this group CRM_Contact_BAO_GroupContactCache::remove(); // delete any dupe cache entry CRM_Core_BAO_PrevNextCache::deleteItem($id); $transaction->commit(); CRM_Utils_Hook::post('delete', $contactType, $contact->id, $contact); // also reset the DB_DO global array so we can reuse the memory // http://issues.civicrm.org/jira/browse/CRM-4387 CRM_Core_DAO::freeResult(); return TRUE; }