/** * Method processAction to execute the action * * @param CRM_Civirules_EventData_EventData $eventData * @access public * */ public function processAction(CRM_Civirules_EventData_EventData $eventData) { $contactId = $eventData->getContactId(); $subTypes = CRM_Contact_BAO_Contact::getContactSubType($contactId); $contactType = CRM_Contact_BAO_Contact::getContactType($contactId); $changed = false; $action_params = $this->getActionParameters(); foreach ($action_params['sub_type'] as $sub_type) { if (CRM_Contact_BAO_ContactType::isExtendsContactType($sub_type, $contactType)) { $subTypes[] = $sub_type; $changed = true; } } if ($changed) { $params['id'] = $contactId; $params['contact_id'] = $contactId; $params['contact_type'] = $contactType; $params['contact_sub_type'] = $subTypes; CRM_Contact_BAO_Contact::add($params); } }
/** * Build all the data structures needed to build the form. */ public function preProcess() { $this->_action = CRM_Utils_Request::retrieve('action', 'String', $this, FALSE, 'add'); $this->_dedupeButtonName = $this->getButtonName('refresh', 'dedupe'); $this->_duplicateButtonName = $this->getButtonName('upload', 'duplicate'); CRM_Core_Resources::singleton()->addStyleFile('civicrm', 'css/contactSummary.css', 2, 'html-header'); $session = CRM_Core_Session::singleton(); if ($this->_action == CRM_Core_Action::ADD) { // check for add contacts permissions if (!CRM_Core_Permission::check('add contacts')) { CRM_Utils_System::permissionDenied(); CRM_Utils_System::civiExit(); } $this->_contactType = CRM_Utils_Request::retrieve('ct', 'String', $this, TRUE, NULL, 'REQUEST'); if (!in_array($this->_contactType, array('Individual', 'Household', 'Organization'))) { CRM_Core_Error::statusBounce(ts('Could not get a contact id and/or contact type')); } $this->_isContactSubType = FALSE; if ($this->_contactSubType = CRM_Utils_Request::retrieve('cst', 'String', $this)) { $this->_isContactSubType = TRUE; } if ($this->_contactSubType && !CRM_Contact_BAO_ContactType::isExtendsContactType($this->_contactSubType, $this->_contactType, TRUE)) { CRM_Core_Error::statusBounce(ts("Could not get a valid contact subtype for contact type '%1'", array(1 => $this->_contactType))); } $this->_gid = CRM_Utils_Request::retrieve('gid', 'Integer', CRM_Core_DAO::$_nullObject, FALSE, NULL, 'GET'); $this->_tid = CRM_Utils_Request::retrieve('tid', 'Integer', CRM_Core_DAO::$_nullObject, FALSE, NULL, 'GET'); $typeLabel = CRM_Contact_BAO_ContactType::contactTypePairs(TRUE, $this->_contactSubType ? $this->_contactSubType : $this->_contactType); $typeLabel = implode(' / ', $typeLabel); CRM_Utils_System::setTitle(ts('New %1', array(1 => $typeLabel))); $session->pushUserContext(CRM_Utils_System::url('civicrm/dashboard', 'reset=1')); $this->_contactId = NULL; } else { //update mode if (!$this->_contactId) { $this->_contactId = CRM_Utils_Request::retrieve('cid', 'Positive', $this, TRUE); } if ($this->_contactId) { $defaults = array(); $params = array('id' => $this->_contactId); $returnProperities = array('id', 'contact_type', 'contact_sub_type', 'modified_date', 'is_deceased'); CRM_Core_DAO::commonRetrieve('CRM_Contact_DAO_Contact', $params, $defaults, $returnProperities); if (empty($defaults['id'])) { CRM_Core_Error::statusBounce(ts('A Contact with that ID does not exist: %1', array(1 => $this->_contactId))); } $this->_contactType = CRM_Utils_Array::value('contact_type', $defaults); $this->_contactSubType = CRM_Utils_Array::value('contact_sub_type', $defaults); // check for permissions $session = CRM_Core_Session::singleton(); if (!CRM_Contact_BAO_Contact_Permission::allow($this->_contactId, CRM_Core_Permission::EDIT)) { CRM_Core_Error::statusBounce(ts('You do not have the necessary permission to edit this contact.')); } $displayName = CRM_Contact_BAO_Contact::displayName($this->_contactId); if ($defaults['is_deceased']) { $displayName .= ' <span class="crm-contact-deceased">(deceased)</span>'; } $displayName = ts('Edit %1', array(1 => $displayName)); // Check if this is default domain contact CRM-10482 if (CRM_Contact_BAO_Contact::checkDomainContact($this->_contactId)) { $displayName .= ' (' . ts('default organization') . ')'; } // omitting contactImage from title for now since the summary overlay css doesn't work outside of our crm-container CRM_Utils_System::setTitle($displayName); $context = CRM_Utils_Request::retrieve('context', 'String', $this); $qfKey = CRM_Utils_Request::retrieve('key', 'String', $this); $urlParams = 'reset=1&cid=' . $this->_contactId; if ($context) { $urlParams .= "&context={$context}"; } if (CRM_Utils_Rule::qfKey($qfKey)) { $urlParams .= "&key={$qfKey}"; } $session->pushUserContext(CRM_Utils_System::url('civicrm/contact/view', $urlParams)); $values = $this->get('values'); // get contact values. if (!empty($values)) { $this->_values = $values; } else { $params = array('id' => $this->_contactId, 'contact_id' => $this->_contactId, 'noRelationships' => TRUE, 'noNotes' => TRUE, 'noGroups' => TRUE); $contact = CRM_Contact_BAO_Contact::retrieve($params, $this->_values, TRUE); $this->set('values', $this->_values); } } else { CRM_Core_Error::statusBounce(ts('Could not get a contact_id and/or contact_type')); } } // parse street address, CRM-5450 $this->_parseStreetAddress = $this->get('parseStreetAddress'); if (!isset($this->_parseStreetAddress)) { $addressOptions = CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'address_options'); $this->_parseStreetAddress = FALSE; if (!empty($addressOptions['street_address']) && !empty($addressOptions['street_address_parsing'])) { $this->_parseStreetAddress = TRUE; } $this->set('parseStreetAddress', $this->_parseStreetAddress); } $this->assign('parseStreetAddress', $this->_parseStreetAddress); $this->_editOptions = $this->get('contactEditOptions'); if (CRM_Utils_System::isNull($this->_editOptions)) { $this->_editOptions = CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'contact_edit_options', TRUE, NULL, FALSE, 'name', TRUE, 'AND v.filter = 0'); $this->set('contactEditOptions', $this->_editOptions); } // build demographics only for Individual contact type if ($this->_contactType != 'Individual' && array_key_exists('Demographics', $this->_editOptions)) { unset($this->_editOptions['Demographics']); } // in update mode don't show notes if ($this->_contactId && array_key_exists('Notes', $this->_editOptions)) { unset($this->_editOptions['Notes']); } $this->assign('editOptions', $this->_editOptions); $this->assign('contactType', $this->_contactType); $this->assign('contactSubType', $this->_contactSubType); //build contact subtype form element, CRM-6864 $buildContactSubType = TRUE; if ($this->_contactSubType && $this->_action & CRM_Core_Action::ADD) { $buildContactSubType = FALSE; } $this->assign('buildContactSubType', $buildContactSubType); // get the location blocks. $this->_blocks = $this->get('blocks'); if (CRM_Utils_System::isNull($this->_blocks)) { $this->_blocks = CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'contact_edit_options', TRUE, NULL, FALSE, 'name', TRUE, 'AND v.filter = 1'); $this->set('blocks', $this->_blocks); } $this->assign('blocks', $this->_blocks); // this is needed for custom data. $this->assign('entityID', $this->_contactId); // also keep the convention. $this->assign('contactId', $this->_contactId); // location blocks. CRM_Contact_Form_Location::preProcess($this); // retain the multiple count custom fields value if (!empty($_POST['hidden_custom'])) { $customGroupCount = CRM_Utils_Array::value('hidden_custom_group_count', $_POST); if ($contactSubType = CRM_Utils_Array::value('contact_sub_type', $_POST)) { $paramSubType = implode(',', $contactSubType); } $this->_getCachedTree = FALSE; unset($customGroupCount[0]); foreach ($customGroupCount as $groupID => $groupCount) { if ($groupCount > 1) { $this->set('groupID', $groupID); //loop the group for ($i = 0; $i <= $groupCount; $i++) { CRM_Custom_Form_CustomData::preProcess($this, NULL, $contactSubType, $i, $this->_contactType); CRM_Contact_Form_Edit_CustomData::buildQuickForm($this); } } } //reset all the ajax stuff, for normal processing if (isset($this->_groupTree)) { $this->_groupTree = NULL; } $this->set('groupID', NULL); $this->_getCachedTree = TRUE; } // execute preProcess dynamically by js else execute normal preProcess if (array_key_exists('CustomData', $this->_editOptions)) { //assign a parameter to pass for sub type multivalue //custom field to load if ($this->_contactSubType || isset($paramSubType)) { $paramSubType = isset($paramSubType) ? $paramSubType : str_replace(CRM_Core_DAO::VALUE_SEPARATOR, ',', trim($this->_contactSubType, CRM_Core_DAO::VALUE_SEPARATOR)); $this->assign('paramSubType', $paramSubType); } if (CRM_Utils_Request::retrieve('type', 'String', CRM_Core_DAO::$_nullObject)) { CRM_Contact_Form_Edit_CustomData::preProcess($this); } else { $contactSubType = $this->_contactSubType; // need contact sub type to build related grouptree array during post process if (!empty($_POST['contact_sub_type'])) { $contactSubType = $_POST['contact_sub_type']; } //only custom data has preprocess hence directly call it CRM_Custom_Form_CustomData::preProcess($this, NULL, $contactSubType, 1, $this->_contactType, $this->_contactId); $this->assign('customValueCount', $this->_customValueCount); } } }
/** * handle the values in import mode * * @param int $onDuplicate the code for what action to take on duplicates * @param array $values the array of values belonging to this line * * @return boolean the result of this processing * @access public */ function import($onDuplicate, &$values, $doGeocodeAddress = false) { $config =& CRM_Core_Config::singleton(); $this->_unparsedStreetAddressContacts = array(); if (!$doGeocodeAddress) { // CRM-5854, reset the geocode method to null to prevent geocoding $config->geocodeMethod = null; } // first make sure this is a valid line //$this->_updateWithId = false; $response = $this->summary($values); $statusFieldName = $this->_statusFieldName; if ($response != CRM_Import_Parser::VALID) { $importRecordParams = array($statusFieldName => 'INVALID', "{$statusFieldName}Msg" => "Invalid (Error Code: {$response})"); $this->updateImportRecord($values[count($values) - 1], $importRecordParams); return $response; } $params =& $this->getActiveFieldParams(); $formatted = array('contact_type' => $this->_contactType); static $contactFields = null; if ($contactFields == null) { require_once "CRM/Contact/DAO/Contact.php"; $contactFields =& CRM_Contact_DAO_Contact::import(); } //check if external identifier exists in database if (CRM_Utils_Array::value('external_identifier', $params) && (CRM_Utils_Array::value('id', $params) || in_array($onDuplicate, array(CRM_Import_Parser::DUPLICATE_SKIP, CRM_Import_Parser::DUPLICATE_NOCHECK)))) { require_once "CRM/Contact/BAO/Contact.php"; if ($internalCid = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $params['external_identifier'], 'id', 'external_identifier')) { if ($internalCid != CRM_Utils_Array::value('id', $params)) { $errorMessage = ts('External Identifier already exists in database.'); array_unshift($values, $errorMessage); $importRecordParams = array($statusFieldName => 'ERROR', "{$statusFieldName}Msg" => $errorMessage); $this->updateImportRecord($values[count($values) - 1], $importRecordParams); return CRM_Import_Parser::ERROR; } } } if (!empty($this->_contactSubType)) { $params['contact_sub_type'] = $this->_contactSubType; } if ($subType = CRM_Utils_Array::value('contact_sub_type', $params)) { if (CRM_Contact_BAO_ContactType::isExtendsContactType($subType, $this->_contactType, false, 'label')) { $subTypes = CRM_Contact_BAO_ContactType::subTypePairs($this->_contactType, false, null); $params['contact_sub_type'] = array_search($subType, $subTypes); } elseif (!CRM_Contact_BAO_ContactType::isExtendsContactType($subType, $this->_contactType)) { $message = "Mismatched or Invalid Contact SubType."; array_unshift($values, $message); return CRM_Import_Parser::NO_MATCH; } } //get contact id to format common data in update/fill mode, //if external identifier is present, CRM-4423 if ($this->_updateWithId && !CRM_Utils_Array::value('id', $params) && CRM_Utils_Array::value('external_identifier', $params)) { if ($cid = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $params['external_identifier'], 'id', 'external_identifier')) { $formatted['id'] = $cid; } } //format common data, CRM-4062 $this->formatCommonData($params, $formatted, $contactFields); $relationship = false; $createNewContact = true; // Support Match and Update Via Contact ID if ($this->_updateWithId) { $createNewContact = false; if (!CRM_Utils_Array::value('id', $params) && CRM_Utils_Array::value('external_identifier', $params)) { if ($cid) { $params['id'] = $cid; } else { //update contact if dedupe found contact id, CRM-4148 $dedupeParams = $formatted; //special case to check dedupe if external id present. //if we send external id dedupe will stop. unset($dedupeParams['external_identifier']); $checkDedupe = _civicrm_duplicate_formatted_contact($dedupeParams); if (civicrm_duplicate($checkDedupe)) { $matchingContactIds = explode(',', $checkDedupe['error_message']['params'][0]); if (count($matchingContactIds) == 1) { $params['id'] = array_pop($matchingContactIds); } else { $message = "More than one matching contact found for given criteria."; array_unshift($values, $message); $this->_retCode = CRM_Import_Parser::NO_MATCH; } } else { $createNewContact = true; } } } $error = _civicrm_duplicate_formatted_contact($formatted); if (civicrm_duplicate($error)) { $matchedIDs = explode(',', $error['error_message']['params'][0]); if (count($matchedIDs) >= 1) { $updateflag = true; foreach ($matchedIDs as $contactId) { if ($params['id'] == $contactId) { $contactType = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $params['id'], 'contact_type'); if ($formatted['contact_type'] == $contactType) { //validation of subtype for update mode //CRM-5125 $contactSubType = null; if (CRM_Utils_Array::value('contact_sub_type', $params)) { $contactSubType = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $params['id'], 'contact_sub_type'); } if (!empty($contactSubType) && (!CRM_Contact_BAO_ContactType::isAllowEdit($params['id'], $contactSubType) || $contactSubType != CRM_Utils_Array::value('contact_sub_type', $formatted))) { $message = "Mismatched contact SubTypes :"; array_unshift($values, $message); $updateflag = false; $this->_retCode = CRM_Import_Parser::NO_MATCH; } else { $newContact = $this->createContact($formatted, $contactFields, $onDuplicate, $contactId, false); $updateflag = false; $this->_retCode = CRM_Import_Parser::VALID; } } else { $message = "Mismatched contact Types :"; array_unshift($values, $message); $updateflag = false; $this->_retCode = CRM_Import_Parser::NO_MATCH; } } } if ($updateflag) { $message = "Mismatched contact IDs OR Mismatched contact Types :"; array_unshift($values, $message); $this->_retCode = CRM_Import_Parser::NO_MATCH; } } } else { $contactType = null; if (CRM_Utils_Array::value('id', $params)) { $contactType = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $params['id'], 'contact_type'); if ($contactType) { if ($formatted['contact_type'] == $contactType) { //validation of subtype for update mode //CRM-5125 $contactSubType = null; if (CRM_Utils_Array::value('contact_sub_type', $params)) { $contactSubType = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $params['id'], 'contact_sub_type'); } if (!empty($contactSubType) && (!CRM_Contact_BAO_ContactType::isAllowEdit($params['id'], $contactSubType) || $contactSubType != CRM_Utils_Array::value('contact_sub_type', $formatted))) { $message = "Mismatched contact SubTypes :"; array_unshift($values, $message); $this->_retCode = CRM_Import_Parser::NO_MATCH; } else { $newContact = $this->createContact($formatted, $contactFields, $onDuplicate, $params['id'], false); $this->_retCode = CRM_Import_Parser::VALID; } } else { $message = "Mismatched contact Types :"; array_unshift($values, $message); $this->_retCode = CRM_Import_Parser::NO_MATCH; } } else { // we should avoid multiple errors for single record // since we have already retCode and we trying to force again. if ($this->_retCode != CRM_Import_Parser::NO_MATCH) { $message = "No contact found for this contact ID:" . $params['id']; array_unshift($values, $message); $this->_retCode = CRM_Import_Parser::NO_MATCH; } } } else { //CRM-4148 //now we want to create new contact on update/fill also. $createNewContact = true; } } if (is_a($newContact, 'CRM_Contact_BAO_Contact')) { $relationship = true; } else { if (is_a($error, 'CRM_Core_Error')) { $newContact = $error; $relationship = true; } } } //fixed CRM-4148 //now we create new contact in update/fill mode also. if ($createNewContact) { //CRM-4430, don't carry if not submitted. foreach (array('prefix', 'suffix', 'gender') as $name) { if (array_key_exists($name, $formatted)) { if (in_array($name, array('prefix', 'suffix'))) { $formattedName = "individual_{$name}"; $formatted[$formattedName] = CRM_Core_OptionGroup::getValue($formattedName, (string) $formatted[$name]); } else { $formatted[$name] = CRM_Core_OptionGroup::getValue($name, (string) $formatted[$name]); } } } $newContact = $this->createContact($formatted, $contactFields, $onDuplicate); } if (is_object($newContact) || $newContact instanceof CRM_Contact_BAO_Contact) { $relationship = true; $newContact = clone $newContact; $this->_newContacts[] = $newContact->id; //get return code if we create new contact in update mode, CRM-4148 if ($this->_updateWithId) { $this->_retCode = CRM_Import_Parser::VALID; } } else { if (civicrm_duplicate($newContact)) { $relationship = true; $contactID = $newContact['error_message']['params'][0]; if (!in_array($contactID, $this->_newContacts)) { $this->_newContacts[] = $contactID; } } } if ($relationship) { $primaryContactId = null; if (civicrm_duplicate($newContact)) { if (CRM_Utils_Rule::integer($newContact['error_message']['params'][0])) { $primaryContactId = $newContact['error_message']['params'][0]; } } else { $primaryContactId = $newContact->id; } if ((civicrm_duplicate($newContact) || is_a($newContact, 'CRM_Contact_BAO_Contact')) && $primaryContactId) { //relationship contact insert foreach ($params as $key => $field) { list($id, $first, $second) = CRM_Utils_System::explode('_', $key, 3); if (!($first == 'a' && $second == 'b') && !($first == 'b' && $second == 'a')) { continue; } $relationType = new CRM_Contact_DAO_RelationshipType(); $relationType->id = $id; $relationType->find(true); $direction = "contact_sub_type_{$second}"; $formatting = array('contact_type' => $params[$key]['contact_type']); //set subtype for related contact CRM-5125 if (isset($relationType->{$direction})) { //validation of related contact subtype for update mode if ($relCsType = CRM_Utils_Array::value('contact_sub_type', $params[$key]) && $relCsType != $relationType->{$direction}) { $errorMessage = ts("Mismatched or Invalid contact subtype found for this related contact"); array_unshift($values, $errorMessage); return CRM_Import_Parser::NO_MATCH; } else { $formatting['contact_sub_type'] = $relationType->{$direction}; } } $relationType->free(); $contactFields = null; $contactFields = CRM_Contact_DAO_Contact::import(); //Relation on the basis of External Identifier. if (!CRM_Utils_Array::value('id', $params[$key]) && isset($params[$key]['external_identifier'])) { $params[$key]['id'] = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $params[$key]['external_identifier'], 'id', 'external_identifier'); } // check for valid related contact id in update/fill mode, CRM-4424 if (in_array($onDuplicate, array(CRM_Import_Parser::DUPLICATE_UPDATE, CRM_Import_Parser::DUPLICATE_FILL)) && CRM_Utils_Array::value('id', $params[$key])) { $relatedContactType = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $params[$key]['id'], 'contact_type'); if (!$relatedContactType) { $errorMessage = ts("No contact found for this related contact ID: %1", array(1 => $params[$key]['id'])); array_unshift($values, $errorMessage); return CRM_Import_Parser::NO_MATCH; } else { //validation of related contact subtype for update mode //CRM-5125 $relatedCsType = null; if (CRM_Utils_Array::value('contact_sub_type', $formatting)) { $relatedCsType = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $params[$key]['id'], 'contact_sub_type'); } if (!empty($relatedCsType) && (!CRM_Contact_BAO_ContactType::isAllowEdit($params[$key]['id'], $relatedCsType) || $relatedCsType != CRM_Utils_Array::value('contact_sub_type', $formatting))) { $errorMessage = ts("Mismatched or Invalid contact subtype found for this related contact ID: %1", array(1 => $params[$key]['id'])); array_unshift($values, $errorMessage); return CRM_Import_Parser::NO_MATCH; } else { // get related contact id to format data in update/fill mode, //if external identifier is present, CRM-4423 $formatting['id'] = $params[$key]['id']; } } } //format common data, CRM-4062 $this->formatCommonData($field, $formatting, $contactFields); //fixed for CRM-4148 if ($params[$key]['id']) { $contact = array('contact_id' => $params[$key]['id']); $defaults = array(); $relatedNewContact = CRM_Contact_BAO_Contact::retrieve($contact, $defaults); } else { $relatedNewContact = $this->createContact($formatting, $contactFields, $onDuplicate, null, false); } if (is_object($relatedNewContact) || $relatedNewContact instanceof CRM_Contact_BAO_Contact) { $relatedNewContact = clone $relatedNewContact; } $matchedIDs = array(); // To update/fill contact, get the matching contact Ids if duplicate contact found // otherwise get contact Id from object of related contact if (is_array($relatedNewContact) && civicrm_error($relatedNewContact)) { if (civicrm_duplicate($relatedNewContact)) { $matchedIDs = explode(',', $relatedNewContact['error_message']['params'][0]); } else { $errorMessage = $relatedNewContact['error_message']; array_unshift($values, $errorMessage); $importRecordParams = array($statusFieldName => 'ERROR', "{$statusFieldName}Msg" => $errorMessage); $this->updateImportRecord($values[count($values) - 1], $importRecordParams); return CRM_Import_Parser::ERROR; } } else { $matchedIDs[] = $relatedNewContact->id; } // update/fill related contact after getting matching Contact Ids, CRM-4424 if (in_array($onDuplicate, array(CRM_Import_Parser::DUPLICATE_UPDATE, CRM_Import_Parser::DUPLICATE_FILL))) { //validation of related contact subtype for update mode //CRM-5125 $relatedCsType = null; if (CRM_Utils_Array::value('contact_sub_type', $formatting)) { $relatedCsType = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $matchedIDs[0], 'contact_sub_type'); } if (!empty($relatedCsType) && (!CRM_Contact_BAO_ContactType::isAllowEdit($matchedIDs[0], $relatedCsType) || $relatedCsType != CRM_Utils_Array::value('contact_sub_type', $formatting))) { $errorMessage = ts("Mismatched or Invalid contact subtype found for this related contact."); array_unshift($values, $errorMessage); return CRM_Import_Parser::NO_MATCH; } else { $updatedContact = $this->createContact($formatting, $contactFields, $onDuplicate, $matchedIDs[0]); } } static $relativeContact = array(); if (civicrm_duplicate($relatedNewContact)) { if (count($matchedIDs) >= 1) { $relContactId = $matchedIDs[0]; //add relative contact to count during update & fill mode. //logic to make count distinct by contact id. if ($this->_newRelatedContacts || !empty($relativeContact)) { $reContact = array_keys($relativeContact, $relContactId); if (empty($reContact)) { $this->_newRelatedContacts[] = $relativeContact[] = $relContactId; } } else { $this->_newRelatedContacts[] = $relativeContact[] = $relContactId; } } } else { $relContactId = $relatedNewContact->id; $this->_newRelatedContacts[] = $relativeContact[] = $relContactId; } if (civicrm_duplicate($relatedNewContact) || $relatedNewContact instanceof CRM_Contact_BAO_Contact) { //fix for CRM-1993.Checks for duplicate related contacts if (count($matchedIDs) >= 1) { //if more than one duplicate contact //found, create relationship with first contact // now create the relationship record $relationParams = array(); $relationParams = array('relationship_type_id' => $key, 'contact_check' => array($relContactId => 1), 'is_active' => 1, 'skipRecentView' => true); // we only handle related contact success, we ignore failures for now // at some point wold be nice to have related counts as separate $relationIds = array('contact' => $primaryContactId); list($valid, $invalid, $duplicate, $saved, $relationshipIds) = CRM_Contact_BAO_Relationship::create($relationParams, $relationIds); CRM_Contact_BAO_Relationship::relatedMemberships($primaryContactId, $relationParams, $relationIds); //handle current employer, CRM-3532 if ($valid) { require_once 'CRM/Core/PseudoConstant.php'; $allRelationships = CRM_Core_PseudoConstant::relationshipType('name'); $relationshipTypeId = str_replace(array('_a_b', '_b_a'), array('', ''), $key); $relationshipType = str_replace($relationshipTypeId . '_', '', $key); $orgId = $individualId = null; if ($allRelationships[$relationshipTypeId]["name_{$relationshipType}"] == 'Employee of') { $orgId = $relContactId; $individualId = $primaryContactId; } else { if ($allRelationships[$relationshipTypeId]["name_{$relationshipType}"] == 'Employer of') { $orgId = $primaryContactId; $individualId = $relContactId; } } if ($orgId && $individualId) { $currentEmpParams[$individualId] = $orgId; require_once 'CRM/Contact/BAO/Contact/Utils.php'; CRM_Contact_BAO_Contact_Utils::setCurrentEmployer($currentEmpParams); } } } } } } } if ($this->_updateWithId) { //return warning if street address is unparsed, CRM-5886 return $this->processMessage($values, $statusFieldName, $this->_retCode); } //dupe checking if (is_array($newContact) && civicrm_error($newContact)) { $code = null; if (($code = CRM_Utils_Array::value('code', $newContact['error_message'])) && $code == CRM_Core_Error::DUPLICATE_CONTACT) { $urls = array(); // need to fix at some stage and decide if the error will return an // array or string, crude hack for now if (is_array($newContact['error_message']['params'][0])) { $cids = $newContact['error_message']['params'][0]; } else { $cids = explode(',', $newContact['error_message']['params'][0]); } foreach ($cids as $cid) { $urls[] = CRM_Utils_System::url('civicrm/contact/view', 'reset=1&cid=' . $cid, true); } $url_string = implode("\n", $urls); // If we duplicate more than one record, skip no matter what if (count($cids) > 1) { $errorMessage = ts('Record duplicates multiple contacts'); $importRecordParams = array($statusFieldName => 'ERROR', "{$statusFieldName}Msg" => $errorMessage); //combine error msg to avoid mismatch between error file columns. $errorMessage .= "\n" . $url_string; array_unshift($values, $errorMessage); $this->updateImportRecord($values[count($values) - 1], $importRecordParams); return CRM_Import_Parser::ERROR; } // Params only had one id, so shift it out $contactId = array_shift($cids); $cid = null; $vals = array('contact_id' => $contactId); if ($onDuplicate == CRM_Import_Parser::DUPLICATE_REPLACE) { $result = civicrm_replace_contact_formatted($contactId, $formatted, $contactFields); $cid = $result['result']; } else { if ($onDuplicate == CRM_Import_Parser::DUPLICATE_UPDATE) { $newContact = $this->createContact($formatted, $contactFields, $onDuplicate, $contactId); } else { if ($onDuplicate == CRM_Import_Parser::DUPLICATE_FILL) { $newContact = $this->createContact($formatted, $contactFields, $onDuplicate, $contactId); } } } // else skip does nothing and just returns an error code. if ($cid) { $contact = array('contact_id' => $cid); $defaults = array(); $newContact = CRM_Contact_BAO_Contact::retrieve($contact, $defaults); } if (civicrm_error($newContact)) { $contactID = $newContact['error_message']['params'][0]; if (!in_array($contactID, $this->_newContacts)) { $this->_newContacts[] = $contactID; } } //CRM-262 No Duplicate Checking if ($onDuplicate == CRM_Import_Parser::DUPLICATE_SKIP) { array_unshift($values, $url_string); $importRecordParams = array($statusFieldName => 'DUPLICATE', "{$statusFieldName}Msg" => "Skipping duplicate record"); $this->updateImportRecord($values[count($values) - 1], $importRecordParams); return CRM_Import_Parser::DUPLICATE; } $importRecordParams = array($statusFieldName => 'IMPORTED'); $this->updateImportRecord($values[count($values) - 1], $importRecordParams); //return warning if street address is not parsed, CRM-5886 return $this->processMessage($values, $statusFieldName, CRM_Import_Parser::VALID); } else { // Not a dupe, so we had an error $errorMessage = $newContact['error_message']; array_unshift($values, $errorMessage); $importRecordParams = array($statusFieldName => 'ERROR', "{$statusFieldName}Msg" => $errorMessage); $this->updateImportRecord($values[count($values) - 1], $importRecordParams); return CRM_Import_Parser::ERROR; } } // sleep(3); return $this->processMessage($values, $statusFieldName, CRM_Import_Parser::VALID); }
/** * Takes an associative array and creates a contact object. * * The function extracts all the params it needs to initialize the create a * contact object. the params array could contain additional unused name/value * pairs * * @param array $params * (reference) an assoc array of name/value pairs. * * @return CRM_Contact_BAO_Contact|CRM_Core_Error|NULL * Created or updated contact object or error object. * (error objects are being phased out in favour of exceptions) */ public static function add(&$params) { $contact = new CRM_Contact_DAO_Contact(); if (empty($params)) { return NULL; } // Fix for validate contact sub type CRM-5143. if (isset($params['contact_sub_type'])) { if (empty($params['contact_sub_type'])) { $params['contact_sub_type'] = 'null'; } else { if (!CRM_Contact_BAO_ContactType::isExtendsContactType($params['contact_sub_type'], $params['contact_type'], TRUE)) { // we'll need to fix tests to handle this // CRM-7925 CRM_Core_Error::fatal(ts('The Contact Sub Type does not match the Contact type for this record')); } if (is_array($params['contact_sub_type'])) { $params['contact_sub_type'] = CRM_Core_DAO::VALUE_SEPARATOR . implode(CRM_Core_DAO::VALUE_SEPARATOR, $params['contact_sub_type']) . CRM_Core_DAO::VALUE_SEPARATOR; } else { $params['contact_sub_type'] = CRM_Core_DAO::VALUE_SEPARATOR . trim($params['contact_sub_type'], CRM_Core_DAO::VALUE_SEPARATOR) . CRM_Core_DAO::VALUE_SEPARATOR; } } } else { // Reset the value. // CRM-101XX. $params['contact_sub_type'] = 'null'; } // Fixed contact source. if (isset($params['contact_source'])) { $params['source'] = $params['contact_source']; } // Fix for preferred communication method. $prefComm = CRM_Utils_Array::value('preferred_communication_method', $params); if ($prefComm && is_array($prefComm)) { unset($params['preferred_communication_method']); $newPref = array(); foreach ($prefComm as $k => $v) { if ($v) { $newPref[$k] = $v; } } $prefComm = $newPref; if (is_array($prefComm) && !empty($prefComm)) { $prefComm = CRM_Core_DAO::VALUE_SEPARATOR . implode(CRM_Core_DAO::VALUE_SEPARATOR, array_keys($prefComm)) . CRM_Core_DAO::VALUE_SEPARATOR; $contact->preferred_communication_method = $prefComm; } else { $contact->preferred_communication_method = ''; } } $allNull = $contact->copyValues($params); $contact->id = CRM_Utils_Array::value('contact_id', $params); if ($contact->contact_type == 'Individual') { $allNull = FALSE; // Format individual fields. CRM_Contact_BAO_Individual::format($params, $contact); } elseif ($contact->contact_type == 'Household') { if (isset($params['household_name'])) { $allNull = FALSE; $contact->display_name = $contact->sort_name = CRM_Utils_Array::value('household_name', $params, ''); } } elseif ($contact->contact_type == 'Organization') { if (isset($params['organization_name'])) { $allNull = FALSE; $contact->display_name = $contact->sort_name = CRM_Utils_Array::value('organization_name', $params, ''); } } $privacy = CRM_Utils_Array::value('privacy', $params); if ($privacy && is_array($privacy) && !empty($privacy)) { $allNull = FALSE; foreach (self::$_commPrefs as $name) { $contact->{$name} = CRM_Utils_Array::value($name, $privacy, FALSE); } } // Since hash was required, make sure we have a 0 value for it (CRM-1063). // @todo - does this mean we can remove this block? // Fixed in 1.5 by making hash optional, only do this in create mode, not update. if ((!array_key_exists('hash', $contact) || !$contact->hash) && !$contact->id) { $allNull = FALSE; $contact->hash = md5(uniqid(rand(), TRUE)); } // Even if we don't need $employerId, it's important to call getFieldValue() before // the contact is saved because we want the existing value to be cached. // createCurrentEmployerRelationship() needs the old value not the updated one. CRM-10788 $employerId = empty($contact->id) ? NULL : CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $contact->id, 'employer_id'); if (!$allNull) { $contact->save(); CRM_Core_BAO_Log::register($contact->id, 'civicrm_contact', $contact->id); } if ($contact->contact_type == 'Individual' && (isset($params['current_employer']) || isset($params['employer_id']))) { // Create current employer. $newEmployer = !empty($params['employer_id']) ? $params['employer_id'] : CRM_Utils_Array::value('current_employer', $params); $newContact = FALSE; if (empty($params['contact_id'])) { $newContact = TRUE; } if ($newEmployer) { CRM_Contact_BAO_Contact_Utils::createCurrentEmployerRelationship($contact->id, $newEmployer, $employerId, $newContact); } else { if ($employerId) { CRM_Contact_BAO_Contact_Utils::clearCurrentEmployer($contact->id, $employerId); } } } // Update cached employer name. if ($contact->contact_type == 'Organization') { CRM_Contact_BAO_Contact_Utils::updateCurrentEmployer($contact->id); } return $contact; }
/** * Get all the registration fields. * * @param int $action * What action are we doing. * @param int $mode * Mode. * * @param null $ctype * * @return array * the fields that are needed for registration */ public static function getRegistrationFields($action, $mode, $ctype = NULL) { if ($mode & CRM_Profile_Form::MODE_REGISTER) { $ufGroups = CRM_Core_BAO_UFGroup::getModuleUFGroup('User Registration'); } else { $ufGroups = CRM_Core_BAO_UFGroup::getModuleUFGroup('Profile'); } if (!is_array($ufGroups)) { return FALSE; } $fields = array(); foreach ($ufGroups as $id => $title) { if ($ctype) { $fieldType = CRM_Core_BAO_UFField::getProfileType($id); if ($fieldType != 'Contact' && $fieldType != $ctype && !CRM_Contact_BAO_ContactType::isExtendsContactType($fieldType, $ctype)) { continue; } if (CRM_Contact_BAO_ContactType::isaSubType($fieldType)) { $profileSubType = $fieldType; } } $subset = self::getFields($id, TRUE, $action, NULL, NULL, FALSE, NULL, TRUE, $ctype); // we do not allow duplicates. the first field is the winner foreach ($subset as $name => $field) { if (empty($fields[$name])) { $fields[$name] = $field; } } } return $fields; }
/** * build all the data structures needed to build the form * * @return void * @access public */ function preProcess() { $this->_action = CRM_Utils_Request::retrieve('action', 'String', $this, FALSE, 'add'); $this->_dedupeButtonName = $this->getButtonName('refresh', 'dedupe'); $this->_duplicateButtonName = $this->getButtonName('upload', 'duplicate'); $session = CRM_Core_Session::singleton(); if ($this->_action == CRM_Core_Action::ADD) { // check for add contacts permissions if (!CRM_Core_Permission::check('add contacts')) { CRM_Utils_System::permissionDenied(); CRM_Utils_System::civiExit(); } $this->_contactType = CRM_Utils_Request::retrieve('ct', 'String', $this, TRUE, NULL, 'REQUEST'); if (!in_array($this->_contactType, array('Individual', 'Household', 'Organization'))) { CRM_Core_Error::statusBounce(ts('Could not get a contact id and/or contact type')); } $this->_isContactSubType = FALSE; if ($this->_contactSubType = CRM_Utils_Request::retrieve('cst', 'String', $this)) { $this->_isContactSubType = TRUE; } if ($this->_contactSubType && !CRM_Contact_BAO_ContactType::isExtendsContactType($this->_contactSubType, $this->_contactType, TRUE)) { CRM_Core_Error::statusBounce(ts("Could not get a valid contact subtype for contact type '%1'", array(1 => $this->_contactType))); } $this->_gid = CRM_Utils_Request::retrieve('gid', 'Integer', CRM_Core_DAO::$_nullObject, FALSE, NULL, 'GET'); $this->_tid = CRM_Utils_Request::retrieve('tid', 'Integer', CRM_Core_DAO::$_nullObject, FALSE, NULL, 'GET'); $typeLabel = CRM_Contact_BAO_ContactType::contactTypePairs(TRUE, $this->_contactSubType ? $this->_contactSubType : $this->_contactType); $typeLabel = implode(' / ', $typeLabel); CRM_Utils_System::setTitle(ts('New %1', array(1 => $typeLabel))); $session->pushUserContext(CRM_Utils_System::url('civicrm/dashboard', 'reset=1')); $this->_contactId = NULL; } else { //update mode if (!$this->_contactId) { $this->_contactId = CRM_Utils_Request::retrieve('cid', 'Positive', $this, TRUE); } if ($this->_contactId) { $defaults = array(); $params = array('id' => $this->_contactId); $returnProperities = array('id', 'contact_type', 'contact_sub_type'); CRM_Core_DAO::commonRetrieve('CRM_Contact_DAO_Contact', $params, $defaults, $returnProperities); if (!CRM_Utils_Array::value('id', $defaults)) { CRM_Core_Error::statusBounce(ts('A Contact with that ID does not exist: %1', array(1 => $this->_contactId))); } $this->_contactType = CRM_Utils_Array::value('contact_type', $defaults); $this->_contactSubType = CRM_Utils_Array::value('contact_sub_type', $defaults); // check for permissions $session = CRM_Core_Session::singleton(); if ($session->get('userID') != $this->_contactId && !CRM_Contact_BAO_Contact_Permission::allow($this->_contactId, CRM_Core_Permission::EDIT)) { CRM_Core_Error::statusBounce(ts('You do not have the necessary permission to edit this contact.')); } list($displayName, $contactImage) = CRM_Contact_BAO_Contact::getDisplayAndImage($this->_contactId); CRM_Utils_System::setTitle($displayName, $contactImage . ' ' . $displayName); $context = CRM_Utils_Request::retrieve('context', 'String', $this); $qfKey = CRM_Utils_Request::retrieve('key', 'String', $this); $urlParams = 'reset=1&cid=' . $this->_contactId; if ($context) { $urlParams .= "&context={$context}"; } if (CRM_Utils_Rule::qfKey($qfKey)) { $urlParams .= "&key={$qfKey}"; } $session->pushUserContext(CRM_Utils_System::url('civicrm/contact/view', $urlParams)); $values = $this->get('values'); // get contact values. if (!empty($values)) { $this->_values = $values; } else { $params = array('id' => $this->_contactId, 'contact_id' => $this->_contactId, 'noRelationships' => TRUE, 'noNotes' => TRUE, 'noGroups' => TRUE); $contact = CRM_Contact_BAO_Contact::retrieve($params, $this->_values, TRUE); $this->set('values', $this->_values); } } else { CRM_Core_Error::statusBounce(ts('Could not get a contact_id and/or contact_type')); } } // parse street address, CRM-5450 $this->_parseStreetAddress = $this->get('parseStreetAddress'); if (!isset($this->_parseStreetAddress)) { $addressOptions = CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'address_options'); $this->_parseStreetAddress = FALSE; if (CRM_Utils_Array::value('street_address', $addressOptions) && CRM_Utils_Array::value('street_address_parsing', $addressOptions)) { $this->_parseStreetAddress = TRUE; } $this->set('parseStreetAddress', $this->_parseStreetAddress); } $this->assign('parseStreetAddress', $this->_parseStreetAddress); $this->_editOptions = $this->get('contactEditOptions'); if (CRM_Utils_System::isNull($this->_editOptions)) { $this->_editOptions = CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'contact_edit_options', TRUE, NULL, FALSE, 'name', TRUE, 'AND v.filter = 0'); $this->set('contactEditOptions', $this->_editOptions); } // build demographics only for Individual contact type if ($this->_contactType != 'Individual' && array_key_exists('Demographics', $this->_editOptions)) { unset($this->_editOptions['Demographics']); } // in update mode don't show notes if ($this->_contactId && array_key_exists('Notes', $this->_editOptions)) { unset($this->_editOptions['Notes']); } $this->assign('editOptions', $this->_editOptions); $this->assign('contactType', $this->_contactType); $this->assign('contactSubType', $this->_contactSubType); //build contact subtype form element, CRM-6864 $buildContactSubType = TRUE; if ($this->_contactSubType && $this->_action & CRM_Core_Action::ADD) { $buildContactSubType = FALSE; } $this->assign('buildContactSubType', $buildContactSubType); // get the location blocks. $this->_blocks = $this->get('blocks'); if (CRM_Utils_System::isNull($this->_blocks)) { $this->_blocks = CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'contact_edit_options', TRUE, NULL, FALSE, 'name', TRUE, 'AND v.filter = 1'); $this->set('blocks', $this->_blocks); } $this->assign('blocks', $this->_blocks); // this is needed for custom data. $this->assign('entityID', $this->_contactId); // also keep the convention. $this->assign('contactId', $this->_contactId); // location blocks. CRM_Contact_Form_Location::preProcess($this); // execute preProcess dynamically by js else execute normal preProcess if (array_key_exists('CustomData', $this->_editOptions)) { if (CRM_Utils_Request::retrieve('type', 'String', CRM_Core_DAO::$_nullObject)) { CRM_Contact_Form_Edit_CustomData::preProcess($this); } else { $contactSubType = $this->_contactSubType; // need contact sub type to build related grouptree array during post process if (CRM_Utils_Array::value('contact_sub_type', $_POST)) { $contactSubType = $_POST['contact_sub_type']; } //only custom data has preprocess hence directly call it CRM_Custom_Form_CustomData::preProcess($this, NULL, $contactSubType, 1, $this->_contactType, $this->_contactId); } } }
/** * get all the registration fields * * @param int $action what action are we doing * @param int $mode mode * * @return array the fields that are needed for registration * @static * @access public */ static function getRegistrationFields($action, $mode, $ctype = null) { if ($mode & CRM_Profile_Form::MODE_REGISTER) { $ufGroups =& CRM_Core_BAO_UFGroup::getModuleUFGroup('User Registration'); } else { $ufGroups =& CRM_Core_BAO_UFGroup::getModuleUFGroup('Profile'); } if (!is_array($ufGroups)) { return false; } $fields = array(); require_once "CRM/Core/BAO/UFField.php"; foreach ($ufGroups as $id => $title) { if ($ctype) { $fieldType = CRM_Core_BAO_UFField::getProfileType($id); if ($fieldType != 'Contact' && $fieldType != $ctype && !CRM_Contact_BAO_ContactType::isExtendsContactType($fieldType, $ctype)) { continue; } if (CRM_Contact_BAO_ContactType::isaSubType($fieldType)) { $profileSubType = $fieldType; } } $subset = self::getFields($id, true, $action, null, null, false, null, true, $ctype); // we do not allow duplicates. the first field is the winner foreach ($subset as $name => $field) { if (!CRM_Utils_Array::value($name, $fields)) { $fields[$name] = $field; } } } return $fields; }
/** * @param array $params * @param bool $dupeCheck * @param bool $dupeErrorArray * @param bool $requiredCheck * @param int $dedupeRuleGroupID * * @return array|null */ function _civicrm_api3_deprecated_contact_check_params(&$params, $dupeCheck = TRUE, $dupeErrorArray = FALSE, $requiredCheck = TRUE, $dedupeRuleGroupID = NULL) { if (isset($params['id']) && is_numeric($params['id'])) { $requiredCheck = FALSE; } if ($requiredCheck) { if (isset($params['id'])) { $required = array('Individual', 'Household', 'Organization'); } $required = array('Individual' => array(array('first_name', 'last_name'), 'email'), 'Household' => array('household_name'), 'Organization' => array('organization_name')); // contact_type has a limited number of valid values if (empty($params['contact_type'])) { return civicrm_api3_create_error("No Contact Type"); } $fields = CRM_Utils_Array::value($params['contact_type'], $required); if ($fields == NULL) { return civicrm_api3_create_error("Invalid Contact Type: {$params['contact_type']}"); } if ($csType = CRM_Utils_Array::value('contact_sub_type', $params)) { if (!CRM_Contact_BAO_ContactType::isExtendsContactType($csType, $params['contact_type'])) { return civicrm_api3_create_error("Invalid or Mismatched Contact Subtype: " . implode(', ', (array) $csType)); } } if (empty($params['contact_id']) && !empty($params['id'])) { $valid = FALSE; $error = ''; foreach ($fields as $field) { if (is_array($field)) { $valid = TRUE; foreach ($field as $element) { if (empty($params[$element])) { $valid = FALSE; $error .= $element; break; } } } else { if (!empty($params[$field])) { $valid = TRUE; } } if ($valid) { break; } } if (!$valid) { return civicrm_api3_create_error("Required fields not found for {$params['contact_type']} : {$error}"); } } } if ($dupeCheck) { // @todo switch to using api version by uncommenting these lines & removing following 11. // Any change here is too scary for a stable release. // $dupes = civicrm_api3('Contact', 'duplicatecheck', (array('match' => $params, 'dedupe_rule_id' => $dedupeRuleGroupID))); // $ids = $dupes['count'] ? implode(',', array_keys($dupes['values'])) : NULL; // check for record already existing require_once 'CRM/Dedupe/Finder.php'; $dedupeParams = CRM_Dedupe_Finder::formatParams($params, $params['contact_type']); // CRM-6431 // setting 'check_permission' here means that the dedupe checking will be carried out even if the // person does not have permission to carry out de-dupes // this is similar to the front end form if (isset($params['check_permission'])) { $dedupeParams['check_permission'] = $params['check_permission']; } $ids = implode(',', CRM_Dedupe_Finder::dupesByParams($dedupeParams, $params['contact_type'], 'Unsupervised', array(), $dedupeRuleGroupID)); if ($ids != NULL) { if ($dupeErrorArray) { $error = CRM_Core_Error::createError("Found matching contacts: {$ids}", CRM_Core_Error::DUPLICATE_CONTACT, 'Fatal', $ids); return civicrm_api3_create_error($error->pop()); } return civicrm_api3_create_error("Found matching contacts: {$ids}"); } } // check for organisations with same name if (!empty($params['current_employer'])) { $organizationParams = array(); $organizationParams['organization_name'] = $params['current_employer']; require_once 'CRM/Dedupe/Finder.php'; $dedupParams = CRM_Dedupe_Finder::formatParams($organizationParams, 'Organization'); $dedupParams['check_permission'] = FALSE; $dupeIds = CRM_Dedupe_Finder::dupesByParams($dedupParams, 'Organization', 'Supervised'); // check for mismatch employer name and id if (!empty($params['employer_id']) && !in_array($params['employer_id'], $dupeIds)) { return civicrm_api3_create_error('Employer name and Employer id Mismatch'); } // show error if multiple organisation with same name exist if (empty($params['employer_id']) && count($dupeIds) > 1) { return civicrm_api3_create_error('Found more than one Organisation with same Name.'); } } return NULL; }
/** * Check parameters passed in. * * This function is on it's way out. * * @param array $params * @param bool $dupeCheck * * @return null * @throws API_Exception * @throws CiviCRM_API3_Exception */ function _civicrm_api3_contact_check_params(&$params, $dupeCheck) { switch (strtolower(CRM_Utils_Array::value('contact_type', $params))) { case 'household': civicrm_api3_verify_mandatory($params, NULL, array('household_name')); break; case 'organization': civicrm_api3_verify_mandatory($params, NULL, array('organization_name')); break; case 'individual': civicrm_api3_verify_one_mandatory($params, NULL, array('first_name', 'last_name', 'email', 'display_name')); break; } // Fixme: This really needs to be handled at a lower level. @See CRM-13123 if (isset($params['preferred_communication_method'])) { $params['preferred_communication_method'] = CRM_Utils_Array::implodePadded($params['preferred_communication_method']); } if (!empty($params['contact_sub_type']) && !empty($params['contact_type'])) { if (!CRM_Contact_BAO_ContactType::isExtendsContactType($params['contact_sub_type'], $params['contact_type'])) { throw new API_Exception("Invalid or Mismatched Contact Subtype: " . implode(', ', (array) $params['contact_sub_type'])); } } if ($dupeCheck) { // check for record already existing $dedupeParams = CRM_Dedupe_Finder::formatParams($params, $params['contact_type']); // CRM-6431 // setting 'check_permission' here means that the dedupe checking will be carried out even if the // person does not have permission to carry out de-dupes // this is similar to the front end form if (isset($params['check_permission'])) { $dedupeParams['check_permission'] = $params['check_permission']; } $ids = CRM_Dedupe_Finder::dupesByParams($dedupeParams, $params['contact_type'], 'Unsupervised', array()); if (count($ids) > 0) { throw new API_Exception("Found matching contacts: " . implode(',', $ids), "duplicate", array("ids" => $ids)); } } // The BAO no longer supports the legacy param "current_employer" so here is a shim for api backward-compatability if (!empty($params['current_employer'])) { $organizationParams = array('organization_name' => $params['current_employer']); $dedupParams = CRM_Dedupe_Finder::formatParams($organizationParams, 'Organization'); $dedupParams['check_permission'] = FALSE; $dupeIds = CRM_Dedupe_Finder::dupesByParams($dedupParams, 'Organization', 'Supervised'); // check for mismatch employer name and id if (!empty($params['employer_id']) && !in_array($params['employer_id'], $dupeIds)) { throw new API_Exception('Employer name and Employer id Mismatch'); } // show error if multiple organisation with same name exist if (empty($params['employer_id']) && count($dupeIds) > 1) { throw new API_Exception('Found more than one Organisation with same Name.'); } if ($dupeIds) { $params['employer_id'] = $dupeIds[0]; } else { $result = civicrm_api3('Contact', 'create', array('organization_name' => $params['current_employer'], 'contact_type' => 'Organization')); $params['employer_id'] = $result['id']; } } return NULL; }
/** * Ensure that we have the right input parameters * * @todo We also need to make sure we run all the form rules on the params list * to ensure that the params are valid * * @param array $params Associative array of property name/value * pairs to insert in new contact. * @param boolean $dupeCheck Should we check for duplicate contacts * @param boolean $dupeErrorArray Should we return values of error * object in array foramt * @param boolean $requiredCheck Should we check if required params * are present in params array * @param int $dedupeRuleGroupID - the dedupe rule ID to use if present * * @return null on success, error message otherwise * @access public */ function civicrm_contact_check_params(&$params, $dupeCheck = TRUE, $dupeErrorArray = FALSE, $requiredCheck = TRUE, $dedupeRuleGroupID = NULL) { if ($requiredCheck) { $required = array('Individual' => array(array('first_name', 'last_name'), 'email'), 'Household' => array('household_name'), 'Organization' => array('organization_name')); // cannot create a contact with empty params if (empty($params)) { return civicrm_create_error('Input Parameters empty'); } if (!array_key_exists('contact_type', $params)) { return civicrm_create_error('Contact Type not specified'); } // contact_type has a limited number of valid values $fields = CRM_Utils_Array::value($params['contact_type'], $required); if ($fields == NULL) { return civicrm_create_error("Invalid Contact Type: {$params['contact_type']}"); } if ($csType = CRM_Utils_Array::value('contact_sub_type', $params)) { if (!CRM_Contact_BAO_ContactType::isExtendsContactType($csType, $params['contact_type'])) { return civicrm_create_error("Invalid or Mismatched Contact SubType: " . implode(', ', (array) $csType)); } } if (!CRM_Utils_Array::value('contact_id', $params)) { $valid = FALSE; $error = ''; foreach ($fields as $field) { if (is_array($field)) { $valid = TRUE; foreach ($field as $element) { if (!CRM_Utils_Array::value($element, $params)) { $valid = FALSE; $error .= $element; break; } } } else { if (CRM_Utils_Array::value($field, $params)) { $valid = TRUE; } } if ($valid) { break; } } if (!$valid) { return civicrm_create_error("Required fields not found for {$params['contact_type']} : {$error}"); } } } if ($dupeCheck) { // check for record already existing require_once 'CRM/Dedupe/Finder.php'; $dedupeParams = CRM_Dedupe_Finder::formatParams($params, $params['contact_type']); // CRM-6431 // setting 'check_permission' here means that the dedupe checking will be carried out even if the // person does not have permission to carry out de-dupes // this is similar to the front end form if (isset($params['check_permission'])) { $dedupeParams['check_permission'] = $fields['check_permission']; } $ids = implode(',', CRM_Dedupe_Finder::dupesByParams($dedupeParams, $params['contact_type'], 'Strict', array(), $dedupeRuleGroupID)); if ($ids != NULL) { if ($dupeErrorArray) { $error = CRM_Core_Error::createError("Found matching contacts: {$ids}", CRM_Core_Error::DUPLICATE_CONTACT, 'Fatal', $ids); return civicrm_create_error($error->pop()); } return civicrm_create_error("Found matching contacts: {$ids}", array($ids)); } } //check for organisations with same name if (CRM_Utils_Array::value('current_employer', $params)) { $organizationParams = array(); $organizationParams['organization_name'] = $params['current_employer']; require_once 'CRM/Dedupe/Finder.php'; $dedupParams = CRM_Dedupe_Finder::formatParams($organizationParams, 'Organization'); $dedupParams['check_permission'] = FALSE; $dupeIds = CRM_Dedupe_Finder::dupesByParams($dedupParams, 'Organization', 'Fuzzy'); // check for mismatch employer name and id if (CRM_Utils_Array::value('employer_id', $params) && !in_array($params['employer_id'], $dupeIds)) { return civicrm_create_error('Employer name and Employer id Mismatch'); } // show error if multiple organisation with same name exist if (!CRM_Utils_Array::value('employer_id', $params) && count($dupeIds) > 1) { return civicrm_create_error('Found more than one Organisation with same Name.'); } } return NULL; }
/** * Handle the values in import mode. * * @param int $onDuplicate * The code for what action to take on duplicates. * @param array $values * The array of values belonging to this line. * * @param bool $doGeocodeAddress * * @return bool * the result of this processing */ public function import($onDuplicate, &$values, $doGeocodeAddress = FALSE) { $config = CRM_Core_Config::singleton(); $this->_unparsedStreetAddressContacts = array(); if (!$doGeocodeAddress) { // CRM-5854, reset the geocode method to null to prevent geocoding $config->geocodeMethod = NULL; } // first make sure this is a valid line //$this->_updateWithId = false; $response = $this->summary($values); $statusFieldName = $this->_statusFieldName; if ($response != CRM_Import_Parser::VALID) { $importRecordParams = array($statusFieldName => 'INVALID', "{$statusFieldName}Msg" => "Invalid (Error Code: {$response})"); $this->updateImportRecord($values[count($values) - 1], $importRecordParams); return $response; } $params =& $this->getActiveFieldParams(); $formatted = array('contact_type' => $this->_contactType); static $contactFields = NULL; if ($contactFields == NULL) { $contactFields = CRM_Contact_DAO_Contact::import(); } //check if external identifier exists in database if (!empty($params['external_identifier']) && (!empty($params['id']) || in_array($onDuplicate, array(CRM_Import_Parser::DUPLICATE_SKIP, CRM_Import_Parser::DUPLICATE_NOCHECK)))) { if ($internalCid = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $params['external_identifier'], 'id', 'external_identifier')) { if ($internalCid != CRM_Utils_Array::value('id', $params)) { $errorMessage = ts('External ID already exists in Database.'); array_unshift($values, $errorMessage); $importRecordParams = array($statusFieldName => 'ERROR', "{$statusFieldName}Msg" => $errorMessage); $this->updateImportRecord($values[count($values) - 1], $importRecordParams); return CRM_Import_Parser::DUPLICATE; } } } if (!empty($this->_contactSubType)) { $params['contact_sub_type'] = $this->_contactSubType; } if ($subType = CRM_Utils_Array::value('contact_sub_type', $params)) { if (CRM_Contact_BAO_ContactType::isExtendsContactType($subType, $this->_contactType, FALSE, 'label')) { $subTypes = CRM_Contact_BAO_ContactType::subTypePairs($this->_contactType, FALSE, NULL); $params['contact_sub_type'] = array_search($subType, $subTypes); } elseif (!CRM_Contact_BAO_ContactType::isExtendsContactType($subType, $this->_contactType)) { $message = "Mismatched or Invalid Contact Subtype."; array_unshift($values, $message); return CRM_Import_Parser::NO_MATCH; } } // Get contact id to format common data in update/fill mode, // prioritising a dedupe rule check over an external_identifier check, but falling back on ext id. if ($this->_updateWithId && empty($params['id'])) { $possibleMatches = $this->getPossibleContactMatches($params); foreach ($possibleMatches as $possibleID) { $params['id'] = $formatted['id'] = $possibleID; } } //format common data, CRM-4062 $this->formatCommonData($params, $formatted, $contactFields); $relationship = FALSE; $createNewContact = TRUE; // Support Match and Update Via Contact ID if ($this->_updateWithId && isset($params['id'])) { $createNewContact = FALSE; // @todo - it feels like all the rows from here to the end of the IF // could be removed in favour of a simple check for whether the contact_type & id match // the call to the deprecated function seems to add no value other that to do an additional // check for the contact_id & type. $error = _civicrm_api3_deprecated_duplicate_formatted_contact($formatted); if (CRM_Core_Error::isAPIError($error, CRM_Core_ERROR::DUPLICATE_CONTACT)) { $matchedIDs = explode(',', $error['error_message']['params'][0]); if (count($matchedIDs) >= 1) { $updateflag = TRUE; foreach ($matchedIDs as $contactId) { if ($params['id'] == $contactId) { $contactType = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $params['id'], 'contact_type'); if ($formatted['contact_type'] == $contactType) { //validation of subtype for update mode //CRM-5125 $contactSubType = NULL; if (!empty($params['contact_sub_type'])) { $contactSubType = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $params['id'], 'contact_sub_type'); } if (!empty($contactSubType) && (!CRM_Contact_BAO_ContactType::isAllowEdit($params['id'], $contactSubType) && $contactSubType != CRM_Utils_Array::value('contact_sub_type', $formatted))) { $message = "Mismatched contact SubTypes :"; array_unshift($values, $message); $updateflag = FALSE; $this->_retCode = CRM_Import_Parser::NO_MATCH; } else { $updateflag = FALSE; $this->_retCode = CRM_Import_Parser::VALID; } } else { $message = "Mismatched contact Types :"; array_unshift($values, $message); $updateflag = FALSE; $this->_retCode = CRM_Import_Parser::NO_MATCH; } } } if ($updateflag) { $message = "Mismatched contact IDs OR Mismatched contact Types :"; array_unshift($values, $message); $this->_retCode = CRM_Import_Parser::NO_MATCH; } } } else { $contactType = NULL; if (!empty($params['id'])) { $contactType = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $params['id'], 'contact_type'); if ($contactType) { if ($formatted['contact_type'] == $contactType) { //validation of subtype for update mode //CRM-5125 $contactSubType = NULL; if (!empty($params['contact_sub_type'])) { $contactSubType = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $params['id'], 'contact_sub_type'); } if (!empty($contactSubType) && (!CRM_Contact_BAO_ContactType::isAllowEdit($params['id'], $contactSubType) && $contactSubType != CRM_Utils_Array::value('contact_sub_type', $formatted))) { $message = "Mismatched contact SubTypes :"; array_unshift($values, $message); $this->_retCode = CRM_Import_Parser::NO_MATCH; } else { $newContact = $this->createContact($formatted, $contactFields, $onDuplicate, $params['id'], FALSE, $this->_dedupeRuleGroupID); $this->_retCode = CRM_Import_Parser::VALID; } } else { $message = "Mismatched contact Types :"; array_unshift($values, $message); $this->_retCode = CRM_Import_Parser::NO_MATCH; } } else { // we should avoid multiple errors for single record // since we have already retCode and we trying to force again. if ($this->_retCode != CRM_Import_Parser::NO_MATCH) { $message = "No contact found for this contact ID:" . $params['id']; array_unshift($values, $message); $this->_retCode = CRM_Import_Parser::NO_MATCH; } } } else { //CRM-4148 //now we want to create new contact on update/fill also. $createNewContact = TRUE; } } if (isset($newContact) && is_a($newContact, 'CRM_Contact_BAO_Contact')) { $relationship = TRUE; } elseif (is_a($error, 'CRM_Core_Error')) { $newContact = $error; $relationship = TRUE; } } //fixed CRM-4148 //now we create new contact in update/fill mode also. $contactID = NULL; if ($createNewContact || $this->_retCode != CRM_Import_Parser::NO_MATCH && $this->_updateWithId) { //CRM-4430, don't carry if not submitted. foreach (array('prefix_id', 'suffix_id', 'gender_id') as $name) { if (!empty($formatted[$name])) { $options = CRM_Contact_BAO_Contact::buildOptions($name, 'get'); if (!isset($options[$formatted[$name]])) { $formatted[$name] = CRM_Utils_Array::key((string) $formatted[$name], $options); } } } if ($this->_updateWithId && !empty($params['id'])) { $contactID = $params['id']; } $newContact = $this->createContact($formatted, $contactFields, $onDuplicate, $contactID, TRUE, $this->_dedupeRuleGroupID); } if (isset($newContact) && is_object($newContact) && $newContact instanceof CRM_Contact_BAO_Contact) { $relationship = TRUE; $newContact = clone $newContact; $contactID = $newContact->id; $this->_newContacts[] = $contactID; //get return code if we create new contact in update mode, CRM-4148 if ($this->_updateWithId) { $this->_retCode = CRM_Import_Parser::VALID; } } elseif (isset($newContact) && CRM_Core_Error::isAPIError($newContact, CRM_Core_ERROR::DUPLICATE_CONTACT)) { // if duplicate, no need of further processing if ($onDuplicate == CRM_Import_Parser::DUPLICATE_SKIP) { $errorMessage = "Skipping duplicate record"; array_unshift($values, $errorMessage); $importRecordParams = array($statusFieldName => 'DUPLICATE', "{$statusFieldName}Msg" => $errorMessage); $this->updateImportRecord($values[count($values) - 1], $importRecordParams); return CRM_Import_Parser::DUPLICATE; } $relationship = TRUE; # see CRM-10433 - might return comma separate list of all dupes $dupeContactIDs = explode(',', $newContact['error_message']['params'][0]); $dupeCount = count($dupeContactIDs); $contactID = array_pop($dupeContactIDs); // check to see if we had more than one duplicate contact id. // if we have more than one, the record will be rejected below if ($dupeCount == 1) { // there was only one dupe, we will continue normally... if (!in_array($contactID, $this->_newContacts)) { $this->_newContacts[] = $contactID; } } } if ($contactID) { // call import hook $currentImportID = end($values); $hookParams = array('contactID' => $contactID, 'importID' => $currentImportID, 'importTempTable' => $this->_tableName, 'fieldHeaders' => $this->_mapperKeys, 'fields' => $this->_activeFields); CRM_Utils_Hook::import('Contact', 'process', $this, $hookParams); } if ($relationship) { $primaryContactId = NULL; if (CRM_Core_Error::isAPIError($newContact, CRM_Core_ERROR::DUPLICATE_CONTACT)) { if (CRM_Utils_Rule::integer($newContact['error_message']['params'][0])) { $primaryContactId = $newContact['error_message']['params'][0]; } } else { $primaryContactId = $newContact->id; } if ((CRM_Core_Error::isAPIError($newContact, CRM_Core_ERROR::DUPLICATE_CONTACT) || is_a($newContact, 'CRM_Contact_BAO_Contact')) && $primaryContactId) { //relationship contact insert foreach ($params as $key => $field) { list($id, $first, $second) = CRM_Utils_System::explode('_', $key, 3); if (!($first == 'a' && $second == 'b') && !($first == 'b' && $second == 'a')) { continue; } $relationType = new CRM_Contact_DAO_RelationshipType(); $relationType->id = $id; $relationType->find(TRUE); $direction = "contact_sub_type_{$second}"; $formatting = array('contact_type' => $params[$key]['contact_type']); //set subtype for related contact CRM-5125 if (isset($relationType->{$direction})) { //validation of related contact subtype for update mode if ($relCsType = CRM_Utils_Array::value('contact_sub_type', $params[$key]) && $relCsType != $relationType->{$direction}) { $errorMessage = ts("Mismatched or Invalid contact subtype found for this related contact."); array_unshift($values, $errorMessage); return CRM_Import_Parser::NO_MATCH; } else { $formatting['contact_sub_type'] = $relationType->{$direction}; } } $relationType->free(); $contactFields = NULL; $contactFields = CRM_Contact_DAO_Contact::import(); //Relation on the basis of External Identifier. if (empty($params[$key]['id']) && !empty($params[$key]['external_identifier'])) { $params[$key]['id'] = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $params[$key]['external_identifier'], 'id', 'external_identifier'); } // check for valid related contact id in update/fill mode, CRM-4424 if (in_array($onDuplicate, array(CRM_Import_Parser::DUPLICATE_UPDATE, CRM_Import_Parser::DUPLICATE_FILL)) && !empty($params[$key]['id'])) { $relatedContactType = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $params[$key]['id'], 'contact_type'); if (!$relatedContactType) { $errorMessage = ts("No contact found for this related contact ID: %1", array(1 => $params[$key]['id'])); array_unshift($values, $errorMessage); return CRM_Import_Parser::NO_MATCH; } else { //validation of related contact subtype for update mode //CRM-5125 $relatedCsType = NULL; if (!empty($formatting['contact_sub_type'])) { $relatedCsType = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $params[$key]['id'], 'contact_sub_type'); } if (!empty($relatedCsType) && (!CRM_Contact_BAO_ContactType::isAllowEdit($params[$key]['id'], $relatedCsType) && $relatedCsType != CRM_Utils_Array::value('contact_sub_type', $formatting))) { $errorMessage = ts("Mismatched or Invalid contact subtype found for this related contact.") . ' ' . ts("ID: %1", array(1 => $params[$key]['id'])); array_unshift($values, $errorMessage); return CRM_Import_Parser::NO_MATCH; } else { // get related contact id to format data in update/fill mode, //if external identifier is present, CRM-4423 $formatting['id'] = $params[$key]['id']; } } } //format common data, CRM-4062 $this->formatCommonData($field, $formatting, $contactFields); //do we have enough fields to create related contact. $allowToCreate = $this->checkRelatedContactFields($key, $formatting); if (!$allowToCreate) { $errorMessage = ts('Related contact required fields are missing.'); array_unshift($values, $errorMessage); return CRM_Import_Parser::NO_MATCH; } //fixed for CRM-4148 if (!empty($params[$key]['id'])) { $contact = array('contact_id' => $params[$key]['id']); $defaults = array(); $relatedNewContact = CRM_Contact_BAO_Contact::retrieve($contact, $defaults); } else { $relatedNewContact = $this->createContact($formatting, $contactFields, $onDuplicate, NULL, FALSE); } if (is_object($relatedNewContact) || $relatedNewContact instanceof CRM_Contact_BAO_Contact) { $relatedNewContact = clone $relatedNewContact; } $matchedIDs = array(); // To update/fill contact, get the matching contact Ids if duplicate contact found // otherwise get contact Id from object of related contact if (is_array($relatedNewContact) && civicrm_error($relatedNewContact)) { if (CRM_Core_Error::isAPIError($relatedNewContact, CRM_Core_ERROR::DUPLICATE_CONTACT)) { $matchedIDs = explode(',', $relatedNewContact['error_message']['params'][0]); } else { $errorMessage = $relatedNewContact['error_message']; array_unshift($values, $errorMessage); $importRecordParams = array($statusFieldName => 'ERROR', "{$statusFieldName}Msg" => $errorMessage); $this->updateImportRecord($values[count($values) - 1], $importRecordParams); return CRM_Import_Parser::ERROR; } } else { $matchedIDs[] = $relatedNewContact->id; } // update/fill related contact after getting matching Contact Ids, CRM-4424 if (in_array($onDuplicate, array(CRM_Import_Parser::DUPLICATE_UPDATE, CRM_Import_Parser::DUPLICATE_FILL))) { //validation of related contact subtype for update mode //CRM-5125 $relatedCsType = NULL; if (!empty($formatting['contact_sub_type'])) { $relatedCsType = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $matchedIDs[0], 'contact_sub_type'); } if (!empty($relatedCsType) && (!CRM_Contact_BAO_ContactType::isAllowEdit($matchedIDs[0], $relatedCsType) && $relatedCsType != CRM_Utils_Array::value('contact_sub_type', $formatting))) { $errorMessage = ts("Mismatched or Invalid contact subtype found for this related contact."); array_unshift($values, $errorMessage); return CRM_Import_Parser::NO_MATCH; } else { $updatedContact = $this->createContact($formatting, $contactFields, $onDuplicate, $matchedIDs[0]); } } static $relativeContact = array(); if (CRM_Core_Error::isAPIError($relatedNewContact, CRM_Core_ERROR::DUPLICATE_CONTACT)) { if (count($matchedIDs) >= 1) { $relContactId = $matchedIDs[0]; //add relative contact to count during update & fill mode. //logic to make count distinct by contact id. if ($this->_newRelatedContacts || !empty($relativeContact)) { $reContact = array_keys($relativeContact, $relContactId); if (empty($reContact)) { $this->_newRelatedContacts[] = $relativeContact[] = $relContactId; } } else { $this->_newRelatedContacts[] = $relativeContact[] = $relContactId; } } } else { $relContactId = $relatedNewContact->id; $this->_newRelatedContacts[] = $relativeContact[] = $relContactId; } if (CRM_Core_Error::isAPIError($relatedNewContact, CRM_Core_ERROR::DUPLICATE_CONTACT) || $relatedNewContact instanceof CRM_Contact_BAO_Contact) { //fix for CRM-1993.Checks for duplicate related contacts if (count($matchedIDs) >= 1) { //if more than one duplicate contact //found, create relationship with first contact // now create the relationship record $relationParams = array(); $relationParams = array('relationship_type_id' => $key, 'contact_check' => array($relContactId => 1), 'is_active' => 1, 'skipRecentView' => TRUE); // we only handle related contact success, we ignore failures for now // at some point wold be nice to have related counts as separate $relationIds = array('contact' => $primaryContactId); list($valid, $invalid, $duplicate, $saved, $relationshipIds) = CRM_Contact_BAO_Relationship::legacyCreateMultiple($relationParams, $relationIds); if ($valid || $duplicate) { $relationIds['contactTarget'] = $relContactId; $action = $duplicate ? CRM_Core_Action::UPDATE : CRM_Core_Action::ADD; CRM_Contact_BAO_Relationship::relatedMemberships($primaryContactId, $relationParams, $relationIds, $action); } //handle current employer, CRM-3532 if ($valid) { $allRelationships = CRM_Core_PseudoConstant::relationshipType('name'); $relationshipTypeId = str_replace(array('_a_b', '_b_a'), array('', ''), $key); $relationshipType = str_replace($relationshipTypeId . '_', '', $key); $orgId = $individualId = NULL; if ($allRelationships[$relationshipTypeId]["name_{$relationshipType}"] == 'Employee of') { $orgId = $relContactId; $individualId = $primaryContactId; } elseif ($allRelationships[$relationshipTypeId]["name_{$relationshipType}"] == 'Employer of') { $orgId = $primaryContactId; $individualId = $relContactId; } if ($orgId && $individualId) { $currentEmpParams[$individualId] = $orgId; CRM_Contact_BAO_Contact_Utils::setCurrentEmployer($currentEmpParams); } } } } } } } if ($this->_updateWithId) { //return warning if street address is unparsed, CRM-5886 return $this->processMessage($values, $statusFieldName, $this->_retCode); } //dupe checking if (is_array($newContact) && civicrm_error($newContact)) { $code = NULL; if (($code = CRM_Utils_Array::value('code', $newContact['error_message'])) && $code == CRM_Core_Error::DUPLICATE_CONTACT) { $urls = array(); // need to fix at some stage and decide if the error will return an // array or string, crude hack for now if (is_array($newContact['error_message']['params'][0])) { $cids = $newContact['error_message']['params'][0]; } else { $cids = explode(',', $newContact['error_message']['params'][0]); } foreach ($cids as $cid) { $urls[] = CRM_Utils_System::url('civicrm/contact/view', 'reset=1&cid=' . $cid, TRUE); } $url_string = implode("\n", $urls); // If we duplicate more than one record, skip no matter what if (count($cids) > 1) { $errorMessage = ts('Record duplicates multiple contacts'); $importRecordParams = array($statusFieldName => 'ERROR', "{$statusFieldName}Msg" => $errorMessage); //combine error msg to avoid mismatch between error file columns. $errorMessage .= "\n" . $url_string; array_unshift($values, $errorMessage); $this->updateImportRecord($values[count($values) - 1], $importRecordParams); return CRM_Import_Parser::ERROR; } // Params only had one id, so shift it out $contactId = array_shift($cids); $cid = NULL; $vals = array('contact_id' => $contactId); if ($onDuplicate == CRM_Import_Parser::DUPLICATE_REPLACE) { civicrm_api('contact', 'delete', $vals); $cid = CRM_Contact_BAO_Contact::createProfileContact($formatted, $contactFields, $contactId, NULL, NULL, $formatted['contact_type']); } elseif ($onDuplicate == CRM_Import_Parser::DUPLICATE_UPDATE) { $newContact = $this->createContact($formatted, $contactFields, $onDuplicate, $contactId); } elseif ($onDuplicate == CRM_Import_Parser::DUPLICATE_FILL) { $newContact = $this->createContact($formatted, $contactFields, $onDuplicate, $contactId); } // else skip does nothing and just returns an error code. if ($cid) { $contact = array('contact_id' => $cid); $defaults = array(); $newContact = CRM_Contact_BAO_Contact::retrieve($contact, $defaults); } if (civicrm_error($newContact)) { if (empty($newContact['error_message']['params'])) { // different kind of error other than DUPLICATE $errorMessage = $newContact['error_message']; array_unshift($values, $errorMessage); $importRecordParams = array($statusFieldName => 'ERROR', "{$statusFieldName}Msg" => $errorMessage); $this->updateImportRecord($values[count($values) - 1], $importRecordParams); return CRM_Import_Parser::ERROR; } $contactID = $newContact['error_message']['params'][0]; if (!in_array($contactID, $this->_newContacts)) { $this->_newContacts[] = $contactID; } } //CRM-262 No Duplicate Checking if ($onDuplicate == CRM_Import_Parser::DUPLICATE_SKIP) { array_unshift($values, $url_string); $importRecordParams = array($statusFieldName => 'DUPLICATE', "{$statusFieldName}Msg" => "Skipping duplicate record"); $this->updateImportRecord($values[count($values) - 1], $importRecordParams); return CRM_Import_Parser::DUPLICATE; } $importRecordParams = array($statusFieldName => 'IMPORTED'); $this->updateImportRecord($values[count($values) - 1], $importRecordParams); //return warning if street address is not parsed, CRM-5886 return $this->processMessage($values, $statusFieldName, CRM_Import_Parser::VALID); } else { // Not a dupe, so we had an error $errorMessage = $newContact['error_message']; array_unshift($values, $errorMessage); $importRecordParams = array($statusFieldName => 'ERROR', "{$statusFieldName}Msg" => $errorMessage); $this->updateImportRecord($values[count($values) - 1], $importRecordParams); return CRM_Import_Parser::ERROR; } } // sleep(3); return $this->processMessage($values, $statusFieldName, CRM_Import_Parser::VALID); }
/** * takes an associative array and creates a contact object * * the function extract all the params it needs to initialize the create a * contact object. the params array could contain additional unused name/value * pairs * * @param array $params (reference ) an assoc array of name/value pairs * * @return object CRM_Contact_BAO_Contact object * @access public * @static */ static function add(&$params) { $contact =& new CRM_Contact_DAO_Contact(); if (empty($params)) { return; } //fix for validate contact sub type CRM-5143 $subType = CRM_Utils_Array::value('contact_sub_type', $params); if ($subType && !CRM_Contact_BAO_ContactType::isExtendsContactType($subType, $params['contact_type'], true)) { return; } //fixed contact source if (isset($params['contact_source'])) { $params['source'] = $params['contact_source']; } //fix for preferred communication method $prefComm = CRM_Utils_Array::value('preferred_communication_method', $params); if ($prefComm && is_array($prefComm)) { unset($params['preferred_communication_method']); $newPref = array(); foreach ($prefComm as $k => $v) { if ($v) { $newPref[$k] = $v; } } $prefComm = $newPref; if (is_array($prefComm) && !empty($prefComm)) { $prefComm = CRM_Core_BAO_CustomOption::VALUE_SEPERATOR . implode(CRM_Core_BAO_CustomOption::VALUE_SEPERATOR, array_keys($prefComm)) . CRM_Core_BAO_CustomOption::VALUE_SEPERATOR; $contact->preferred_communication_method = $prefComm; } else { $contact->preferred_communication_method = ''; } } $allNull = $contact->copyValues($params); $contact->id = CRM_Utils_Array::value('contact_id', $params); if ($contact->contact_type == 'Individual') { $allNull = false; //format individual fields require_once "CRM/Contact/BAO/Individual.php"; CRM_Contact_BAO_Individual::format($params, $contact); } else { if ($contact->contact_type == 'Household') { if (isset($params['household_name'])) { $allNull = false; $contact->display_name = $contact->sort_name = CRM_Utils_Array::value('household_name', $params, ''); } } else { if ($contact->contact_type == 'Organization') { if (isset($params['organization_name'])) { $allNull = false; $contact->display_name = $contact->sort_name = CRM_Utils_Array::value('organization_name', $params, ''); } } } } // privacy block $privacy = CRM_Utils_Array::value('privacy', $params); if ($privacy && is_array($privacy) && !empty($privacy)) { $allNull = false; foreach (self::$_commPrefs as $name) { $contact->{$name} = CRM_Utils_Array::value($name, $privacy, false); } } // since hash was required, make sure we have a 0 value for it, CRM-1063 // fixed in 1.5 by making hash optional // only do this in create mode, not update if ((!array_key_exists('hash', $contact) || !$contact->hash) && !$contact->id) { $allNull = false; $contact->hash = md5(uniqid(rand(), true)); } if (!$allNull) { $contact->save(); require_once 'CRM/Core/BAO/Log.php'; CRM_Core_BAO_Log::register($contact->id, 'civicrm_contact', $contact->id); } if ($contact->contact_type == 'Individual' && array_key_exists('current_employer', $params)) { // create current employer if ($params['current_employer']) { require_once 'CRM/Contact/BAO/Contact/Utils.php'; CRM_Contact_BAO_Contact_Utils::createCurrentEmployerRelationship($contact->id, $params['current_employer']); } else { //unset if employer id exits if ($employerId = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $contact->id, 'employer_id')) { require_once 'CRM/Contact/BAO/Contact/Utils.php'; CRM_Contact_BAO_Contact_Utils::clearCurrentEmployer($contact->id, $employerId); } } } //update cached employee name if ($contact->contact_type == 'Organization') { require_once 'CRM/Contact/BAO/Contact/Utils.php'; CRM_Contact_BAO_Contact_Utils::updateCurrentEmployer($contact->id); } return $contact; }
/** * Ensure that we have the right input parameters * * @todo We also need to make sure we run all the form rules on the params list * to ensure that the params are valid * * @param array $params Associative array of property name/value * pairs to insert in new contact. * @param boolean $dupeCheck Should we check for duplicate contacts * @param boolean $dupeErrorArray Should we return values of error * object in array foramt * @param boolean $requiredCHeck Should we check if required params * are present in params array * * @return null on success, error message otherwise * @access public */ function civicrm_contact_check_params(&$params, $dupeCheck = true, $dupeErrorArray = false, $requiredCheck = true) { if ($requiredCheck) { $required = array('Individual' => array(array('first_name', 'last_name'), 'email'), 'Household' => array('household_name'), 'Organization' => array('organization_name')); // cannot create a contact with empty params if (empty($params)) { return civicrm_create_error('Input Parameters empty'); } if (!array_key_exists('contact_type', $params)) { return civicrm_create_error('Contact Type not specified'); } // contact_type has a limited number of valid values $fields = CRM_Utils_Array::value($params['contact_type'], $required); if ($fields == null) { return civicrm_create_error("Invalid Contact Type: {$params['contact_type']}"); } if ($csType = CRM_Utils_Array::value('contact_sub_type', $params)) { if (!CRM_Contact_BAO_ContactType::isExtendsContactType($csType, $params['contact_type'])) { return civicrm_create_error("Invalid or Mismatched Contact SubType: {$csType}"); } } if (!CRM_Utils_Array::value('contact_id', $params)) { $valid = false; $error = ''; foreach ($fields as $field) { if (is_array($field)) { $valid = true; foreach ($field as $element) { if (!CRM_Utils_Array::value($element, $params)) { $valid = false; $error .= $element; break; } } } else { if (CRM_Utils_Array::value($field, $params)) { $valid = true; } } if ($valid) { break; } } if (!$valid) { return civicrm_create_error("Required fields not found for {$params['contact_type']} : {$error}"); } } } if ($dupeCheck) { // check for record already existing require_once 'CRM/Dedupe/Finder.php'; $dedupeParams = CRM_Dedupe_Finder::formatParams($params, $params['contact_type']); $ids = implode(',', CRM_Dedupe_Finder::dupesByParams($dedupeParams, $params['contact_type'])); if ($ids != null) { if ($dupeErrorArray) { $error = CRM_Core_Error::createError("Found matching contacts: {$ids}", CRM_Core_Error::DUPLICATE_CONTACT, 'Fatal', $ids); return civicrm_create_error($error->pop()); } return civicrm_create_error("Found matching contacts: {$ids}", $ids); } } return null; }
function _civicrm_api3_contact_check_params(&$params, $dupeCheck = true, $dupeErrorArray = false, $obsoletevalue = true, $dedupeRuleGroupID = null) { switch (strtolower(CRM_Utils_Array::value('contact_type', $params))) { case 'household': civicrm_api3_verify_mandatory($params, null, array('household_name')); break; case 'organization': civicrm_api3_verify_mandatory($params, null, array('organization_name')); break; case 'individual': civicrm_api3_verify_one_mandatory($params, null, array('first_name', 'last_name', 'email', 'display_name')); break; } if (CRM_Utils_Array::value('contact_sub_type', $params) && CRM_Utils_Array::value('contact_type', $params)) { if (!CRM_Contact_BAO_ContactType::isExtendsContactType($params['contact_sub_type'], $params['contact_type'])) { return civicrm_api3_create_error("Invalid or Mismatched Contact SubType: " . implode(', ', (array) $params['contact_sub_type'])); } } if ($dupeCheck) { // check for record already existing require_once 'CRM/Dedupe/Finder.php'; $dedupeParams = CRM_Dedupe_Finder::formatParams($params, $params['contact_type']); // CRM-6431 // setting 'check_permission' here means that the dedupe checking will be carried out even if the // person does not have permission to carry out de-dupes // this is similar to the front end form if (isset($params['check_permission'])) { $dedupeParams['check_permission'] = $params['check_permission']; } $ids = implode(',', CRM_Dedupe_Finder::dupesByParams($dedupeParams, $params['contact_type'], 'Strict', array())); if ($ids != NULL) { throw new Exception("Found matching contacts: {$ids}"); } } //check for organisations with same name if (CRM_Utils_Array::value('current_employer', $params)) { $organizationParams = array(); $organizationParams['organization_name'] = $params['current_employer']; require_once 'CRM/Dedupe/Finder.php'; $dedupParams = CRM_Dedupe_Finder::formatParams($organizationParams, 'Organization'); $dedupParams['check_permission'] = FALSE; $dupeIds = CRM_Dedupe_Finder::dupesByParams($dedupParams, 'Organization', 'Fuzzy'); // check for mismatch employer name and id if (CRM_Utils_Array::value('employer_id', $params) && !in_array($params['employer_id'], $dupeIds)) { return civicrm_api3_create_error('Employer name and Employer id Mismatch'); } // show error if multiple organisation with same name exist if (!CRM_Utils_Array::value('employer_id', $params) && count($dupeIds) > 1) { return civicrm_api3_create_error('Found more than one Organisation with same Name.'); } } return NULL; }