X-Git-Url: https://vcs.fsf.org/?a=blobdiff_plain;ds=sidebyside;f=CRM%2FDedupe%2FMerger.php;h=17daf65be2795afd4dd39c5c0c83d0c4ad9a9fab;hb=c301f76e83796cab7a73e8edf3129013f23cf339;hp=71a49129f15f5c94953c6c724288da22e57a213f;hpb=ab2e3179d57fbd8b60c0730ec38b6cb678100a28;p=civicrm-core.git diff --git a/CRM/Dedupe/Merger.php b/CRM/Dedupe/Merger.php index 71a49129f1..17daf65be2 100644 --- a/CRM/Dedupe/Merger.php +++ b/CRM/Dedupe/Merger.php @@ -1,7 +1,7 @@ array('IN' => array('Individual', 'Organization', 'Household', 'Contact')), 'return' => array('id', 'title', 'table_name', 'style'), )); - foreach($result['values'] as $custom) { + foreach ($result['values'] as $custom) { $data['cidRefs'][$custom['table_name']] = array('entity_id'); $urlSuffix = $custom['style'] == 'Tab' ? '&selectedChild=custom_' . $custom['id'] : ''; $data['relTables']['rel_table_custom_' . $custom['id']] = array( @@ -290,7 +291,7 @@ WHERE * Tables which require custom processing should declare functions to call here. * Doing so will override normal processing. */ - static function cpTables() { + public static function cpTables() { static $tables; if (!$tables) { $tables = array( @@ -307,7 +308,7 @@ WHERE /** * Return payment related table. */ - static function paymentTables() { + public static function paymentTables() { static $tables; if (!$tables) { $tables = array('civicrm_pledge', 'civicrm_membership', 'civicrm_participant'); @@ -319,7 +320,7 @@ WHERE /** * Return payment update Query. */ - static function paymentSql($tableName, $mainContactId, $otherContactId) { + public static function paymentSql($tableName, $mainContactId, $otherContactId) { $sqls = array(); if (!$tableName || !$mainContactId || !$otherContactId) { return $sqls; @@ -371,34 +372,34 @@ INNER JOIN civicrm_participant participant ON ( participant.id = payment.partic * * @return array */ - static function operationSql($mainId, $otherId, $tableName, $tableOperations = array(), $mode = 'add') { + public static function operationSql($mainId, $otherId, $tableName, $tableOperations = array(), $mode = 'add') { $sqls = array(); if (!$tableName || !$mainId || !$otherId) { return $sqls; } - switch ($tableName) { case 'civicrm_membership': - if (array_key_exists($tableName, $tableOperations) && $tableOperations[$tableName]['add']) - break; - if ($mode == 'add') { - $sqls[] = " + if (array_key_exists($tableName, $tableOperations) && $tableOperations[$tableName]['add']) { + break; + } + if ($mode == 'add') { + $sqls[] = " DELETE membership1.* FROM civicrm_membership membership1 INNER JOIN civicrm_membership membership2 ON membership1.membership_type_id = membership2.membership_type_id AND membership1.contact_id = {$mainId} AND membership2.contact_id = {$otherId} "; - } - if ($mode == 'payment') { - $sqls[] = " + } + if ($mode == 'payment') { + $sqls[] = " DELETE contribution.* FROM civicrm_contribution contribution INNER JOIN civicrm_membership_payment payment ON payment.contribution_id = contribution.id INNER JOIN civicrm_membership membership1 ON membership1.id = payment.membership_id AND membership1.contact_id = {$mainId} INNER JOIN civicrm_membership membership2 ON membership1.membership_type_id = membership2.membership_type_id AND membership2.contact_id = {$otherId}"; - } - break; + } + break; case 'civicrm_uf_match': // normal queries won't work for uf_match since that will lead to violation of unique constraint, @@ -414,9 +415,8 @@ INNER JOIN civicrm_membership membership2 ON membership1.membership_type_id = m * Based on the provided two contact_ids and a set of tables, move the * belongings of the other contact to the main one. * - * @static */ - static function moveContactBelongings($mainId, $otherId, $tables = FALSE, $tableOperations = array()) { + public static function moveContactBelongings($mainId, $otherId, $tables = FALSE, $tableOperations = array()) { $cidRefs = self::cidRefs(); $eidRefs = self::eidRefs(); $cpTables = self::cpTables(); @@ -517,13 +517,14 @@ INNER JOIN civicrm_membership membership2 ON membership1.membership_type_id = m /** * Find differences between contacts. * - * @param array $main contact details - * @param array $other contact details + * @param array $main + * Contact details. + * @param array $other + * Contact details. * * @return array - * @static */ - static function findDifferences($main, $other) { + public static function findDifferences($main, $other) { $result = array( 'contact' => array(), 'custom' => array(), @@ -554,19 +555,21 @@ INNER JOIN civicrm_membership membership2 ON membership1.membership_type_id = m /** * Batch merge a set of contacts based on rule-group and group. * - * @param int $rgid rule group id - * @param int $gid group id - * @param string $mode helps decide how to behave when there are conflicts. + * @param int $rgid + * Rule group id. + * @param int $gid + * Group id. + * @param string $mode + * Helps decide how to behave when there are conflicts. * A 'safe' value skips the merge if there are any un-resolved conflicts. * Does a force merge otherwise. - * @param boolean $autoFlip wether to let api decide which contact to retain and which to delete. + * @param bool $autoFlip to let api decide which contact to retain and which to delete. + * Wether to let api decide which contact to retain and which to delete. * @param bool $redirectForPerformance * * @return array|bool - * @static - * @access public */ - static function batchMerge($rgid, $gid = NULL, $mode = 'safe', $autoFlip = TRUE, $redirectForPerformance = FALSE) { + public static function batchMerge($rgid, $gid = NULL, $mode = 'safe', $autoFlip = TRUE, $redirectForPerformance = FALSE) { $contactType = CRM_Core_DAO::getFieldValue('CRM_Dedupe_DAO_RuleGroup', $rgid, 'contact_type'); $cacheKeyString = "merge {$contactType}"; $cacheKeyString .= $rgid ? "_{$rgid}" : '_0'; @@ -596,23 +599,25 @@ INNER JOIN civicrm_membership membership2 ON membership1.membership_type_id = m /** * Merge given set of contacts. Performs core operation. * - * @param array $dupePairs set of pair of contacts for whom merge is to be done. - * @param array $cacheParams prev-next-cache params based on which next pair of contacts are computed. + * @param array $dupePairs + * Set of pair of contacts for whom merge is to be done. + * @param array $cacheParams + * Prev-next-cache params based on which next pair of contacts are computed. * Generally used with batch-merge. - * @param string $mode helps decide how to behave when there are conflicts. + * @param string $mode + * Helps decide how to behave when there are conflicts. * A 'safe' value skips the merge if there are any un-resolved conflicts. * Does a force merge otherwise (aggressive mode). - * @param boolean $autoFlip wether to let api decide which contact to retain and which to delete. + * @param bool $autoFlip to let api decide which contact to retain and which to delete. + * Wether to let api decide which contact to retain and which to delete. * * * @param bool $redirectForPerformance * * @return array|bool - * @static - * @access public */ - static function merge($dupePairs = array(), $cacheParams = array(), $mode = 'safe', - $autoFlip = TRUE, $redirectForPerformance = FALSE + public static function merge($dupePairs = array(), $cacheParams = array(), $mode = 'safe', + $autoFlip = TRUE, $redirectForPerformance = FALSE ) { $cacheKeyString = CRM_Utils_Array::value('cache_key_string', $cacheParams); $resultStats = array('merged' => array(), 'skipped' => array()); @@ -687,18 +692,20 @@ INNER JOIN civicrm_membership membership2 ON membership1.membership_type_id = m * A function which uses various rules / algorithms for choosing which contact to bias to * when there's a conflict (to handle "gotchas"). Plus the safest route to merge. * - * @param int $mainId main contact with whom merge has to happen - * @param int $otherId duplicate contact which would be deleted after merge operation - * @param array $migrationInfo array of information about which elements to merge. - * @param string $mode helps decide how to behave when there are conflicts. + * @param int $mainId + * Main contact with whom merge has to happen. + * @param int $otherId + * Duplicate contact which would be deleted after merge operation. + * @param array $migrationInfo + * Array of information about which elements to merge. + * @param string $mode + * Helps decide how to behave when there are conflicts. * A 'safe' value skips the merge if there are any un-resolved conflicts. * Does a force merge otherwise (aggressive mode). * * @return bool - * @static - * @access public */ - static function skipMerge($mainId, $otherId, &$migrationInfo, $mode = 'safe') { + public static function skipMerge($mainId, $otherId, &$migrationInfo, $mode = 'safe') { $conflicts = array(); $migrationData = array( 'old_migration_info' => $migrationInfo, @@ -714,7 +721,8 @@ INNER JOIN civicrm_membership membership2 ON membership1.membership_type_id = m } elseif ((in_array(substr($key, 5), CRM_Dedupe_Merger::getContactFields()) or substr($key, 0, 12) == 'move_custom_' - ) and $val != NULL) { + ) and $val != NULL + ) { // Rule: if both main-contact has other-contact, let $mode decide if to merge a // particular field or not if (!empty($migrationInfo['rows'][$key]['main'])) { @@ -739,7 +747,8 @@ INNER JOIN civicrm_membership membership2 ON membership1.membership_type_id = m if ($fieldName == 'address') { $mainNewLocTypeId = $migrationInfo['location'][$fieldName][$fieldCount]['locTypeId']; if (!empty($migrationInfo['main_loc_address']) && - array_key_exists("main_{$mainNewLocTypeId}", $migrationInfo['main_loc_address'])) { + array_key_exists("main_{$mainNewLocTypeId}", $migrationInfo['main_loc_address']) + ) { // main loc already has some address for the loc-type. Its a overwrite situation. // look for next available loc-type @@ -799,19 +808,23 @@ INNER JOIN civicrm_membership membership2 ON membership1.membership_type_id = m /** * 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 + * @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 - * @static - * @access public */ - static function getRowsElementsAndInfo($mainId, $otherId) { + 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())); + $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'])) { @@ -826,9 +839,6 @@ INNER JOIN civicrm_membership membership2 ON membership1.membership_type_id = m CRM_Core_DAO::freeResult(); } - // get all contact subtypes - $contactSubTypes = CRM_Contact_BAO_ContactType::subTypePairs(NULL, TRUE, ''); - // FIXME: there must be a better way foreach (array('main', 'other') as $moniker) { $contact = &$$moniker; @@ -836,37 +846,22 @@ INNER JOIN civicrm_membership membership2 ON membership1.membership_type_id = m $value = empty($preferred_communication_method) ? array() : $preferred_communication_method; $specialValues[$moniker] = array( 'preferred_communication_method' => $value, - 'contact_sub_type' => $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']; + 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( + 'preferred_communication_method' => array( 'newName' => 'preferred_communication_method_display', 'groupName' => 'preferred_communication_method', ), ); CRM_Core_OptionGroup::lookupValues($specialValues[$moniker], $names); - if (!empty($contact['contact_sub_type'])) { - $specialValues[$moniker]['contact_sub_type'] = implode(CRM_Core_DAO::VALUE_SEPARATOR, $contact['contact_sub_type']); - - // fix contact sub type label for contact with sub type - $subtypes = array(); - foreach ($contact['contact_sub_type'] as $key => $value) { - $subtypes[] = CRM_Utils_Array::retrieveValueRecursive($contactSubTypes, $value); - } - $contact['contact_sub_type_display'] = $specialValues[$moniker]['contact_sub_type_display'] = implode(', ', $subtypes); - } - if (!empty($contact['communication_style'])) { $specialValues[$moniker]['communication_style_id_display'] = $contact['communication_style']; } @@ -887,6 +882,10 @@ INNER JOIN civicrm_membership membership2 ON membership1.membership_type_id = m $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); @@ -1039,7 +1038,7 @@ INNER JOIN civicrm_membership membership2 ON membership1.membership_type_id = m array( 1 => $block, 2 => $count, - 3 => $allLocationTypes[$locTypeId] + 3 => $allLocationTypes[$locTypeId], ) ); @@ -1058,8 +1057,11 @@ INNER JOIN civicrm_membership membership2 ON membership1.membership_type_id = m $js = array('onChange' => "mergeBlock('$name', this, $count );"); } $elements[] = array( - 'select', "location[{$name}][$count][locTypeId]", NULL, - $defaultLocType + $locTypeValues, $js, + '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; @@ -1173,9 +1175,9 @@ INNER JOIN civicrm_membership membership2 ON membership1.membership_type_id = m ); if ($values['data'] === 0 || $values['data'] === '0') { $values['data'] = $qfZeroBug; - } + } $value = ($values['data']) ? $values['data'] : $value; - } + } } $rows["move_custom_$fid"]['title'] = $field['label']; @@ -1206,16 +1208,16 @@ INNER JOIN civicrm_membership membership2 ON membership1.membership_type_id = m * other contact to the main one - be it Location / CustomFields or Contact .. related info. * A superset of moveContactBelongings() function. * - * @param int $mainId main contact with whom merge has to happen - * @param int $otherId duplicate contact which would be deleted after merge operation + * @param int $mainId + * Main contact with whom merge has to happen. + * @param int $otherId + * Duplicate contact which would be deleted after merge operation. * * @param $migrationInfo * * @return bool - * @static - * @access public */ - static function moveAllBelongings($mainId, $otherId, $migrationInfo) { + public static function moveAllBelongings($mainId, $otherId, $migrationInfo) { if (empty($migrationInfo)) { return FALSE; } @@ -1228,7 +1230,7 @@ INNER JOIN civicrm_membership membership2 ON membership1.membership_type_id = m $value = '0'; } if ((in_array(substr($key, 5), CRM_Dedupe_Merger::getContactFields()) || - substr($key, 0, 12) == 'move_custom_') && + substr($key, 0, 12) == 'move_custom_') && $value != NULL ) { $submitted[substr($key, 5)] = $value; @@ -1258,7 +1260,6 @@ INNER JOIN civicrm_membership membership2 ON membership1.membership_type_id = m } } - // **** Do location related migration: if (!empty($locBlocks)) { $locComponent = array( @@ -1294,7 +1295,7 @@ INNER JOIN civicrm_membership membership2 ON membership1.membership_type_id = m } if (isset($migrationInfo['main_details']['loc_block_ids'][$name])) { - $mainBlockId = CRM_Utils_Array::value($idKey, $migrationInfo['main_details']['loc_block_ids'][$name]); + $mainBlockId = CRM_Utils_Array::value($idKey, $migrationInfo['main_details']['loc_block_ids'][$name]); } if (!$otherBlockId) { @@ -1426,10 +1427,13 @@ INNER JOIN civicrm_membership membership2 ON membership1.membership_type_id = m //keep state and country as array format. //for checkbox and m-select format w/ VALUE_SEPARATOR if (in_array($htmlType, array( - 'CheckBox', 'Multi-Select', 'AdvMulti-Select'))) { + 'CheckBox', + 'Multi-Select', + 'AdvMulti-Select', + ))) { $submitted[$key] = CRM_Core_DAO::VALUE_SEPARATOR . implode(CRM_Core_DAO::VALUE_SEPARATOR, - $mergeValue - ) . CRM_Core_DAO::VALUE_SEPARATOR; + $mergeValue + ) . CRM_Core_DAO::VALUE_SEPARATOR; } else { $submitted[$key] = $mergeValue; @@ -1437,7 +1441,9 @@ INNER JOIN civicrm_membership membership2 ON membership1.membership_type_id = m } } elseif (in_array($htmlType, array( - 'Multi-Select Country', 'Multi-Select State/Province'))) { + 'Multi-Select Country', + 'Multi-Select State/Province', + ))) { //we require submitted values should be in array format if ($value) { $mergeValueArray = explode(CRM_Core_DAO::VALUE_SEPARATOR, $value); @@ -1486,18 +1492,19 @@ INNER JOIN civicrm_membership membership2 ON membership1.membership_type_id = m // move the other contact's file to main contact //NYSS need to INSERT or UPDATE depending on whether main contact has an existing record - if ( CRM_Core_DAO::singleValueQuery("SELECT id FROM {$tableName} WHERE entity_id = {$mainId}") ) { - $sql = "UPDATE {$tableName} SET {$columnName} = {$fileIds[$otherId]} WHERE entity_id = {$mainId}"; + if (CRM_Core_DAO::singleValueQuery("SELECT id FROM {$tableName} WHERE entity_id = {$mainId}")) { + $sql = "UPDATE {$tableName} SET {$columnName} = {$fileIds[$otherId]} WHERE entity_id = {$mainId}"; } else { $sql = "INSERT INTO {$tableName} ( entity_id, {$columnName} ) VALUES ( {$mainId}, {$fileIds[$otherId]} )"; } CRM_Core_DAO::executeQuery($sql, CRM_Core_DAO::$_nullArray); - if ( CRM_Core_DAO::singleValueQuery(" + if (CRM_Core_DAO::singleValueQuery(" SELECT id FROM civicrm_entity_file - WHERE entity_table = '{$tableName}' AND file_id = {$fileIds[$otherId]}") ) { + WHERE entity_table = '{$tableName}' AND file_id = {$fileIds[$otherId]}") + ) { $sql = " UPDATE civicrm_entity_file SET entity_id = {$mainId} @@ -1551,6 +1558,15 @@ INNER JOIN civicrm_membership membership2 ON membership1.membership_type_id = m /* } */ + // CRM-15681 merge sub_types + if ($other_sub_types = CRM_Utils_array::value('contact_sub_type', $migrationInfo['other_details'])) { + if ($main_sub_types = CRM_Utils_array::value('contact_sub_type', $migrationInfo['main_details'])) { + $submitted['contact_sub_type'] = array_unique(array_merge($main_sub_types, $other_sub_types)); + } + else { + $submitted['contact_sub_type'] = $other_sub_types; + } + } // **** Update contact related info for the main contact if (!empty($submitted)) { @@ -1560,17 +1576,18 @@ INNER JOIN civicrm_membership membership2 ON membership1.membership_type_id = m if ($currentEmloyerId = CRM_Utils_Array::value('current_employer_id', $submitted)) { if (!CRM_Utils_System::isNull($currentEmloyerId)) { $submitted['current_employer'] = $submitted['current_employer_id']; - } else { + } + else { $submitted['current_employer'] = ''; } unset($submitted['current_employer_id']); } //CRM-14312 include prefix/suffix from mainId if not overridden for proper construction of display/sort name - if ( !isset($submitted['prefix_id']) && !empty($migrationInfo['main_details']['prefix_id']) ) { + if (!isset($submitted['prefix_id']) && !empty($migrationInfo['main_details']['prefix_id'])) { $submitted['prefix_id'] = $migrationInfo['main_details']['prefix_id']; } - if ( !isset($submitted['suffix_id']) && !empty($migrationInfo['main_details']['suffix_id']) ) { + if (!isset($submitted['suffix_id']) && !empty($migrationInfo['main_details']['suffix_id'])) { $submitted['suffix_id'] = $migrationInfo['main_details']['suffix_id']; } @@ -1578,16 +1595,29 @@ INNER JOIN civicrm_membership membership2 ON membership1.membership_type_id = m unset($submitted); } + CRM_Utils_Hook::post('merge', 'Contact', $mainId, CRM_Core_DAO::$_nullObject); + return TRUE; } /** - * @return array of field names which will be compared, so everything except ID. + * @return array + * Array of field names which will be compared, so everything except ID. */ - static function getContactFields() { + public static function getContactFields() { $contactFields = CRM_Contact_DAO_Contact::fields(); - $invalidFields = array('api_key', 'contact_is_deleted', 'created_date', 'display_name', 'hash', 'id', 'modified_date', - 'primary_contact_id', 'sort_name', 'user_unique_id'); + $invalidFields = array( + 'api_key', + 'contact_is_deleted', + 'created_date', + 'display_name', + 'hash', + 'id', + 'modified_date', + 'primary_contact_id', + 'sort_name', + 'user_unique_id', + ); foreach ($contactFields as $field => $value) { if (in_array($field, $invalidFields)) { unset($contactFields[$field]); @@ -1598,12 +1628,12 @@ INNER JOIN civicrm_membership membership2 ON membership1.membership_type_id = m /** * Added for CRM-12695 - * Based on the contactId provided + * Based on the contactID provided * add/update membership(s) to related contacts * - * @param contactId + * @param int $contactID */ - static function addMembershipToRealtedContacts($contactID) { + public static function addMembershipToRealtedContacts($contactID) { $dao = new CRM_Member_DAO_Membership(); $dao->contact_id = $contactID; $dao->is_test = 0; @@ -1621,7 +1651,7 @@ INNER JOIN civicrm_membership membership2 ON membership1.membership_type_id = m 'start_date' => CRM_Utils_Date::isoToMysql($dao->start_date), 'end_date' => CRM_Utils_Date::isoToMysql($dao->end_date), 'source' => $dao->source, - 'status_id' => $dao->status_id + 'status_id' => $dao->status_id, ); // create/update membership(s) for related contact(s) CRM_Member_BAO_Membership::createRelatedMemberships($membershipParams, $dao);