From 087f00ec2e01ef5f7bb3022eee01044c64332604 Mon Sep 17 00:00:00 2001 From: JKingsnorth Date: Fri, 20 Nov 2015 16:17:35 +0000 Subject: [PATCH] Initial major refactor --- CRM/Dedupe/Merger.php | 440 ++++++++++++++++++------------------------ 1 file changed, 187 insertions(+), 253 deletions(-) diff --git a/CRM/Dedupe/Merger.php b/CRM/Dedupe/Merger.php index 5d4c4cfed9..085ef2942e 100644 --- a/CRM/Dedupe/Merger.php +++ b/CRM/Dedupe/Merger.php @@ -810,9 +810,6 @@ INNER JOIN civicrm_membership membership2 ON membership1.membership_type_id = m ); $allLocationTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Address', 'location_type_id'); - $allPhoneTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Phone', 'phone_type_id'); - $allProviderTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_IM', 'provider_id'); - $allWebsiteTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Website', 'website_type_id'); foreach ($migrationInfo as $key => $val) { if ($val === "null") { @@ -917,11 +914,13 @@ INNER JOIN civicrm_membership membership2 ON membership1.membership_type_id = m public static function getRowsElementsAndInfo($mainId, $otherId) { $qfZeroBug = 'e8cddb72-a257-11dc-b9cc-0016d3330ee9'; - $allLocationTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Address', 'location_type_id'); - $allPhoneTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Phone', 'phone_type_id'); - $allProviderTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_IM', 'provider_id'); - $allWebsiteTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Website', 'website_type_id'); - $genders = CRM_Core_PseudoConstant::get('CRM_Contact_DAO_Contact', 'gender_id'); + $listOptions = array( + 'location_type_id' => CRM_Core_PseudoConstant::get('CRM_Core_DAO_Address', 'location_type_id'), + 'phone_type_id' => CRM_Core_PseudoConstant::get('CRM_Core_DAO_Phone', 'phone_type_id'), + 'provider_id' => CRM_Core_PseudoConstant::get('CRM_Core_DAO_IM', 'provider_id'), + 'website_type_id' => CRM_Core_PseudoConstant::get('CRM_Core_DAO_Website', 'website_type_id'), + 'gender_id' => CRM_Core_PseudoConstant::get('CRM_Contact_DAO_Contact', 'gender_id'), + ); // Fetch contacts foreach (array('main' => $mainId, 'other' => $otherId) as $moniker => $cid) { @@ -1024,7 +1023,7 @@ INNER JOIN civicrm_membership membership2 ON membership1.membership_type_id = m $field = 'suffix_id'; } elseif ($field == 'gender_id' && !empty($value)) { - $label = $genders[$value]; + $label = $listOptions['gender_id'][$value]; } elseif ($field == 'current_employer_id' && !empty($value)) { $label = "$value (" . CRM_Contact_BAO_Contact::displayName($value) . ")"; @@ -1056,302 +1055,237 @@ INNER JOIN civicrm_membership membership2 ON membership1.membership_type_id = m // Handle location blocks. // @todo OpenID not in API yet, so is not supported here. + // Set up useful information about the location blocks $locationBlocks = array( - 'address' => 'Address', - 'email' => 'Email', - 'im' => 'IM', - 'phone' => 'Phone', - 'website' => 'Website', + 'address' => array( + 'label' => 'Address', + 'displayField' => 'display', + 'sortString' => 'location_type_id', + 'hasLocation' => TRUE, + 'hasType' => FALSE, + ), + 'email' => array( + 'label' => 'Email', + 'displayField' => 'email', + 'sortString' => 'location_type_id', + 'hasLocation' => TRUE, + 'hasType' => FALSE, + ), + 'im' => array( + 'label' => 'IM', + 'displayField' => 'name', + 'sortString' => 'location_type_id,provider_id', + 'hasLocation' => TRUE, + 'hasType' => 'provider_id', + ), + 'phone' => array( + 'label' => 'Phone', + 'displayField' => 'phone', + 'sortString' => 'location_type_id,phone_type_id', + 'hasLocation' => TRUE, + 'hasType' => 'phone_type_id', + ), + 'website' => array( + 'label' => 'Website', + 'displayField' => 'url', + 'sortString' => 'website_type_id', + 'hasLocation' => FALSE, + 'hasType' => 'website_type_id', + ), + ); + + $locations = array( + 'main' => array(), + 'other' => array(), ); - $locations = array(); + $mainLocBlock = $locBlockIds = array(); + $locBlockIds['main'] = $locBlockIds['other'] = array(); + $typeBlockIds['main'] = $typeBlockIds['other'] = array(); + + // @todo This could probably be defined and used earlier + $mergeTargets = array( + 'main' => $mainId, + 'other' => $otherId, + ); + + + foreach ($locationBlocks as $blockName => $blockInfo) { - foreach ($locationBlocks as $blockName => $block) { - foreach (array('main' => $mainId, 'other' => $otherId) as $moniker => $cid) { + // 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, + // CRM-17556 Order by field-specific criteria + 'options' => array( + 'sort' => $blockInfo['sortString'], + ), ); - // CRM-17556 Order by location and type - // Handle websites (no location, only type) - if ($blockName == 'website') { - $searchParams['options'] = array('sort' => 'website_type_id'); - } - // Sort by location and type - elseif ($blockName == 'phone') { - $searchParams['options'] = array('sort' => 'location_type_id,phone_type_id'); - } - elseif ($blockName == 'im') { - $searchParams['options'] = array('sort' => 'location_type_id,provider_id'); - } - // Sort by just location - else { - $searchParams['options'] = array('sort' => 'location_type_id'); - } $values = civicrm_api($blockName, 'get', $searchParams); - $count = $values['count']; - if ($count) { - if ($count > $cnt) { - foreach ($values['values'] as $value) { - if ($blockName == 'address') { - CRM_Core_BAO_Address::fixAddress($value); - $display = CRM_Utils_Address::format($value); - $locations[$moniker][$blockName][$cnt] = $value; - $locations[$moniker][$blockName][$cnt]['display'] = $display; - } - else { - $locations[$moniker][$blockName][$cnt] = $value; - } - - $cnt++; - } - } - else { - $id = $values['id']; + if ($values['count']) { + $cnt = 0; + foreach ($values['values'] as $index => $value) { + $locations[$moniker][$blockName][$cnt] = $value; + // Fix address display if ($blockName == 'address') { - CRM_Core_BAO_Address::fixAddress($values['values'][$id]); - $display = CRM_Utils_Address::format($values['values'][$id]); - $locations[$moniker][$blockName][$cnt] = $values['values'][$id]; + CRM_Core_BAO_Address::fixAddress($value); + $display = CRM_Utils_Address::format($value); $locations[$moniker][$blockName][$cnt]['display'] = $display; } - else { - $locations[$moniker][$blockName][$cnt] = $values['values'][$id]; - } + $cnt++; } } } - } - $mainLocBlock = $locBlockIds = array(); - $locBlockIds['main'] = $locBlockIds['other'] = array(); - $typeBlockIds['main'] = $typeBlockIds['other'] = array(); + // Now, build the table rows appropriately, based off the information on + // the 'other' contact + if (!empty($locations['other'])) { + foreach ($locations['other'] as $count => $value) { - foreach ($locationBlocks as $blockName => $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; - $typeValue[$moniker][$name] = 0; - $locLabel[$moniker][$name] = $locTypes[$moniker][$name] = $typeTypes[$moniker][$name] = array(); - } - else { - $locValue[$moniker][$name] = TRUE; - foreach ($blockValue as $count => $blkValues) { - - // CRM-17556 Handle the different field settings (locations, types, etc.) - $fldName = $name; - $typeTypeId = NULL; - if ($name == 'email') { - $locTypeId = $blkValues['location_type_id']; - $locTypes[$moniker][$name][$count] = $locTypeId; - } - elseif ($name == 'im') { - $fldName = 'name'; - $locTypeId = $blkValues['location_type_id']; - $locTypes[$moniker][$name][$count] = $locTypeId; - $typeTypeId = $blkValues['provider_id']; - $typeTypes[$moniker][$name][$count] = $typeTypeId; - $typeValue[$moniker][$name] = TRUE; - } - elseif ($name == 'address') { - $fldName = 'display'; - $locTypeId = $blkValues['location_type_id']; - $locTypes[$moniker][$name][$count] = $locTypeId; - } - elseif ($name == 'website') { - $fldName = 'url'; - // Websites have a dummy location type ID, but we don't add it to the 'locTypes' array - // @todo There'll be a better way of handling this - $locTypeId = 0; - $typeTypeId = $blkValues['website_type_id']; - $typeTypes[$moniker][$name][$count] = $typeTypeId; - $typeValue[$moniker][$name] = TRUE; - } - elseif ($name == 'phone') { - $locTypeId = $blkValues['location_type_id']; - $locTypes[$moniker][$name][$count] = $locTypeId; - $typeTypeId = $blkValues['phone_type_id']; - $typeTypes[$moniker][$name][$count] = $typeTypeId; - $typeValue[$moniker][$name] = TRUE; - } + // @todo Temporary declarations for compatibility + $name = $blockName; + $block = $blockInfo['label']; - $locLabel[$moniker][$name][$count] = CRM_Utils_Array::value($fldName, $blkValues); + $displayValue = $value[$blockInfo['displayField']]; - // CRM-17556 Add the type (provider) ID to storage - if (!empty($typeTypeId)) { - $typeBlockIds[$moniker][$name][$typeTypeId] = $blkValues['id']; - } + // Add this value to the table rows + $rows["move_location_{$blockName}_{$count}"]['other'] = $displayValue; - // For the 'main' contact - if ($moniker == 'main') { + // CRM-17556 Only display 'main' contact value if it's the same location + type + // Look it up from main values... - // Add this block to the list of 'main' location blocks - // There is a location type, but not necessarily a provider/type (Facebook/mobile/etc.) - if (empty($typeTypeId)) { - $mainLocBlock["main_" . $name . "_" . $locTypeId] = CRM_Utils_Array::value($fldName, $blkValues); - } - else { - $mainLocBlock["main_" . $name . "_" . $locTypeId . "_" . $typeTypeId] = CRM_Utils_Array::value($fldName, $blkValues); - } + $lookupLocation = FALSE; + if ($blockInfo['hasLocation']) { + $lookupLocation = $value['location_type_id']; + } - // Add this block to the list of location block IDs for the 'main' contact - $locBlockIds['main'][$name][$locTypeId] = $blkValues['id']; + $lookupType = FALSE; + if ($blockInfo['hasType']) { + $lookupType = $value[$blockInfo['hasType']]; + } + 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 against the 'other' contact value + $rows["move_location_{$blockName}_{$count}"]['main'] = $mainValueCheck[$blockInfo['displayField']]; + break; + } } + } - // For the 'other' contact - else { - // Add this block to the list of location block IDs for the 'other' contact - // @todo - why is this 'count' not 'locTypeId'? - $locBlockIds['other'][$name][$count] = $blkValues['id']; - } + // 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; - // Build the selection boxes for changing the location and type on the 'main' contact side of the form + // Setup variables + $thisTypeId = FALSE; + $thisLocId = FALSE; - // Websites are skipped later as they don't have location but do have a type - foreach ($locLabel['other'][$name] as $count => $value) { - $rows["move_location_{$name}_$count"]['other'] = $value; - $rows["move_location_{$name}_$count"]['main'] = CRM_Utils_Array::value($count, $locLabel['main'][$name]); + // Provide a select drop-down for the location's location type + // eg: Home, Work... - // CRM-17556 Set up JS lookup of 'main' contact's value by type - $js = NULL; - if (!empty($mainLocBlock)) { - $js = array('onChange' => "mergeBlock('$name', this, $count, 'typeTypeId' );"); - } + $js = NULL; - // Select box for type/provider - switch ($name) { - - case 'im': - $locTypeId = $locTypes['other'][$name][$count]; - $typeTypeId = $typeTypes['other'][$name][$count]; - // make sure default type type is always on top - $mainTypeTypeId = CRM_Utils_Array::value($count, $typeTypes['main'][$name], $typeTypeId); - $typeTypeValues = $allProviderTypes; - $defaultTypeType = array($mainTypeTypeId => $typeTypeValues[$mainTypeTypeId]); - unset($typeTypeValues[$mainTypeTypeId]); - $elements[] = array( - 'select', - "type[$name][$count][typeTypeId]", - NULL, - $defaultTypeType + $typeTypeValues, - $js, - ); - $migrationInfo['type'][$name][$count]['typeTypeId'] = $typeTypeId; - $rows["move_location_{$name}_$count"]['title'] = ts('%1:%2:%3:%4', - array( - 1 => $block, - 2 => $count, - 3 => $allLocationTypes[$locTypeId], - 4 => $allProviderTypes[$typeTypeId], - ) - ); - break; + if ($blockInfo['hasLocation']) { + + // 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']; - case 'phone': - $locTypeId = $locTypes['other'][$name][$count]; - $typeTypeId = $typeTypes['other'][$name][$count]; - // make sure default type type is always on top - $mainTypeTypeId = CRM_Utils_Array::value($count, $typeTypes['main'][$name], $typeTypeId); - $typeTypeValues = $allPhoneTypes; - $defaultTypeType = array($mainTypeTypeId => $typeTypeValues[$mainTypeTypeId]); - unset($typeTypeValues[$mainTypeTypeId]); + // Put this field's location type at the top of the list + $tmpIdList = $listOptions['location_type_id']; + $defaultLocId = array($thisLocId => $tmpIdList[$thisLocId]); + unset($tmpIdList[$thisLocId]); + + // Add the element $elements[] = array( 'select', - "type[$name][$count][typeTypeId]", + "location[$name][$count][locTypeId]", NULL, - $defaultTypeType + $typeTypeValues, + $defaultLocId + $tmpIdList, $js, ); - $migrationInfo['type'][$name][$count]['typeTypeId'] = $typeTypeId; - $rows["move_location_{$name}_$count"]['title'] = ts('%1:%2:%3:%4', - array( - 1 => $block, - 2 => $count, - 3 => $allLocationTypes[$locTypeId], - 4 => $allPhoneTypes[$typeTypeId], - ) - ); - break; - case 'website': - $typeTypeId = $typeTypes['other'][$name][$count]; - // make sure default type type is always on top - $mainTypeTypeId = CRM_Utils_Array::value($count, $typeTypes['main'][$name], $typeTypeId); - $typeTypeValues = $allWebsiteTypes; - $defaultTypeType = array($mainTypeTypeId => $typeTypeValues[$mainTypeTypeId]); - unset($typeTypeValues[$mainTypeTypeId]); + // 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 ($name != 'address') { + $elements[] = array('advcheckbox', "location[{$name}][$count][operation]", NULL, ts('add new')); + // always use add operation + $migrationInfo['location_blocks'][$name][$count]['operation'] = 1; + } + + } + + // Provide a select drop-down for the location's type/provider + // eg websites: Google+, Facebook... + + // CRM-17556 Set up JS lookup of 'main' contact's value by type + $js = NULL; + + if ($blockInfo['hasType']) { + + // JS lookup 'main' contact's location (if there are any) + if (!empty($locations['main'][$blockName])) { + $js = array('onChange' => "mergeBlock('$name', this, $count, 'typeTypeId' );"); + } + + $thisTypeId = $value[$blockInfo['hasType']]; + + // Put this field's location type at the top of the list + $tmpIdList = $listOptions[$blockInfo['hasType']]; + $defaultTypeId = array($thisTypeId => $tmpIdList[$thisTypeId]); + unset($tmpIdList[$thisTypeId]); + + // Add the element $elements[] = array( 'select', "type[$name][$count][typeTypeId]", NULL, - $defaultTypeType + $typeTypeValues, + $defaultTypeId + $tmpIdList, $js, ); - $migrationInfo['type'][$name][$count]['typeTypeId'] = $typeTypeId; - $rows["move_location_{$name}_$count"]['title'] = ts('%1:%2:%3', - array( - 1 => $block, - 2 => $count, - 3 => $allWebsiteTypes[$typeTypeId], - ) - ); - break; - default: - $locTypeId = $locTypes['other'][$name][$count]; - $rows["move_location_{$name}_$count"]['title'] = ts('%1:%2:%3', - array( - 1 => $block, - 2 => $count, - 3 => $allLocationTypes[$locTypeId], - ) - ); - } + // Add the information to the migrationInfo (@todo Why?) + $migrationInfo['location_blocks'][$name][$count]['typeTypeId'] = $typeTypeId; - // CRM-17556 Set up JS lookup of 'main' contact's value by location - $js = NULL; - if (!empty($mainLocBlock)) { - $js = array('onChange' => "mergeBlock('$name', this, $count, 'locTypeId' );"); - } + } - // Add checkbox to migrate data from 'other' to 'main' - $elements[] = array('advcheckbox', "move_location_{$name}_{$count}"); - - // Add location select list for location block (websites don't have a location) - if ($name != 'website') { - $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. - $elements[] = array( - 'select', - "location[$name][$count][locTypeId]", - NULL, - $defaultLocType + $locTypeValues, - $js, + // Set the label for this row + // @todo Reformat for website, empty brackets are lazy and ugly + $rows["move_location_{$name}_$count"]['title'] = ts('%1 %2 (%3) (%4)', + array( + 1 => $blockInfo['label'], + 2 => $count, + 3 => $thisLocId ? $listOptions['location_type_id'][$thisLocId] : ''; + 4 => $thisTypeId ? $listOptions[$blockInfo['hasType']][$thisTypeId] : ''; + ) ); - // 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; - } + + // End loop through 'other' locations of this type } + // End if 'other' location for this type exists } + + // End loop through each location block entity } + // @todo NEW REFACOTRING DONE UP TO HERE + // 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); -- 2.25.1