private function contact_create($mode = 'import') { $this->import_status_update('contact'); // bug fix for $this->contacts keep being appended if (!empty($this->contacts)) { unset($this->contacts); $this->contacts = array(); } for ($i = 0; $i < count($this->csv->data); $i++) { $param = array('version' => '3', 'contact_type' => 'Individual'); if ($mode == 'import') { $param['dupe_check'] = $this->data->dupe_check == 1 ? TRUE : FALSE; // #FIX issue 87: auto-append contact source if it is not mapped // appending the date and the job id to the import if (!in_array('contact_source', $this->contacts)) { $param['contact_source'] = date('Ymd') . '_' . $this->data->jobid; } // #FIX issue 72: Add email only de-dupe feature if ($this->data->dupe_check == 2) { $mapping = array_flip($this->contact_data); $email = $this->csv->data[$i][$mapping['email']]; $contact_id = $this->check_email($email); if (is_numeric($contact_id)) { // for email only dedupe, we delete the param and skip this iteration $this->log->_log('Error on CSV line ' . $i . ':, (Matching contact found:, ' . $contact_id . '),' . implode(',', $this->csv->data[$i]), 'error_csv'); unset($param); continue; } } } // in case we are doing an append with *ONLY* Location data we still need to fill $this->contact if (count($this->contact_data) == 1) { $id = array_values($this->contact_data); $column = array_keys($this->contact_data); if ($id[0] == 'external_identifier') { $contact_id = $this->fetch_contact_id($this->csv->data[$i][$column[0]]); } else { $contact_id = $this->csv->data[$i][$column[0]]; } if (isset($contact_id) && $contact_id != '') { $this->contacts[$contact_id] = $this->csv->data[$i]; } else { // unmatched append row $this->log->_log('Record not found in database:,' . implode(',', $this->csv->data[$i]), 'error_csv'); } } else { foreach ($this->contact_data as $column => $field) { // dealing with some special fields because of CiviCRM's internal workings switch ($field) { case 'birth_date': $param[$field] = civicrm_import_utils::format_date($this->csv->data[$i][$column], $this->data->date_format); break; case 'gender': $param[$field] = civicrm_import_utils::format_gender($this->csv->data[$i][$column]); break; // in appending job you have to get contact_id if they choose to match to external identifier // in appending job you have to get contact_id if they choose to match to external identifier case 'external_identifier': // get the contact id if ($mode == 'import') { $param[$field] = $this->csv->data[$i][$column]; } else { $param['contact_id'] = $this->fetch_contact_id($this->csv->data[$i][$column]); } break; default: $param[$field] = $this->csv->data[$i][$column]; break; } } // print_r($param); // data filtering validation: // if the $param does not fit our validation requirement // i.e. First name, Last name, Email, we do not import them. // #FEATURE: $this->check_filter should return an array of bad fields so we can pin them down in // the log if ($this->check_filter($param, $mode)) { if ($mode == 'import') { // @CiviCRM API (v3) $contact = civicrm_api('contact', 'create', $param); } else { if (isset($param['contact_id']) && $param['contact_id'] != '') { // @CiviCRM API (v3) $param['id'] = $param['contact_id']; unset($param['contact_id']); $contact = civicrm_api('contact', 'create', $param); } else { // log all the ones that did not find a matching record into the error_csv $this->log->_log('Error on CSV line ' . $i . ':, (No matching contact found with the id provided),' . implode(',', $this->csv->data[$i]), 'error_csv'); } } // #FIXED: memory leak from API call CRM_Core_DAO::freeResult(); if ($contact['is_error'] == 1) { $this->log->_log('Error on CSV line ' . $i . ':, (' . $contact['error_message'] . '),' . implode(',', $this->csv->data[$i]), 'error_csv'); } else { $this->contacts[$contact['id']] = $this->csv->data[$i]; $this->contact_imported++; // record the contact import count for tracking if ($this->contact_imported % 100 == 0) { $this->update_count('contact'); } } } else { // log this row as bad row $this->log->_log('Error on CSV line ' . $i . ':, (Bad last name or email on CSV line),' . implode(',', $this->csv->data[$i]), 'error_csv'); } $this->update_count('contact'); } } $this->log->_log($this->contact_imported . ' number of contact records created from ' . count($this->csv->data) . ' number of rows read from CSV file'); // free the original parsed csv from memory unset($this->csv->data); }
public function validate_custom_fields($mapping = array(), $csv_filepath, $depth = 100, $csv_log = FALSE) { $this->log->__set('logging', $csv_log); # 1st, get the import data to see if there's any custom fields // $mappings = unserialize($this->data->mapping); $custom_fields_mapping = array(); $custom_fields_mapping_set = array(); foreach ($mapping as $column => $field) { if (strstr($field, 'custom_')) { $custom_fields_mapping[$column] = substr($field, 7, 8); // just want the custom field id } } // if there's no custom fields to import, don't waste time if (!empty($custom_fields_mapping)) { # 2nd, are they radios, checkboxes or selections? (SET values) foreach ($custom_fields_mapping as $column => $custom_field_id) { $custom_field_type = $this->db->get_var(sprintf("SELECT html_type FROM civicrm_custom_field WHERE id = %d", $custom_field_id)); if ($custom_field_type == 'Select' || $custom_field_type == 'CheckBox' || $custom_field_type == 'Radio') { $custom_fields_mapping_set[$column] = $custom_field_id; } } // only care if the custom field we import has set values if (!empty($custom_fields_mapping_set)) { # 3rd, fetch the expected set values of the custom fields $errors = 0; foreach ($custom_fields_mapping_set as $column => $custom_field_id) { $query = sprintf("SELECT cov.value FROM civicrm_option_value cov \n\t\t\t\t\tJOIN civicrm_option_group cog ON cov.option_group_id = cog.id\n\t\t\t\t\tJOIN civicrm_custom_field ccf ON ccf.option_group_id = cog.id\n\t\t\t\t\tWHERE ccf.option_group_id IS NOT NULL AND ccf.id = %d", $custom_field_id); if ($results = $this->db->get_results($query, ARRAY_N)) { # 4 match the fields with csv data $_res = civicrm_import_utils::flattenArray($results); #4.1 parse limited data $this->csv->offset = 1; $this->csv->limit = $depth; $this->csv->parse($csv_filepath); for ($i = 0; $i < count($this->csv->data); $i++) { if (!in_array($this->csv->data[$i][$column], $_res)) { $errors++; // mark the error and log the data validation error $this->csv->data[$i][$column] .= ' [acceptable values are: ' . implode(',', $_res) . ']'; $this->log->_log($this->csv->unparse(array($this->csv->data[$i])), 'error_csv', FALSE); } } } } // end of foreach if ($errors > 0) { // Trigger error email and point or attach the error csv report and include the message below // echo $errors . " Error(s) occured. Inconsistent custom data detected, this import job is cancelled"; $this->custom_field_errors = $errors; return FALSE; } // At this point we are successful? unset($this->csv->data); return TRUE; } } else { // if no custom field detected, just return TRUE return TRUE; } }