2 if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
4 /*********************************************************************************
5 * SugarCRM Community Edition is a customer relationship management program developed by
6 * SugarCRM, Inc. Copyright (C) 2004-2012 SugarCRM Inc.
8 * This program is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU Affero General Public License version 3 as published by the
10 * Free Software Foundation with the addition of the following permission added
11 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
12 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
13 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
15 * This program is distributed in the hope that it will be useful, but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
20 * You should have received a copy of the GNU Affero General Public License along with
21 * this program; if not, see http://www.gnu.org/licenses or write to the Free
22 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
26 * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
28 * The interactive user interfaces in modified source and object code versions
29 * of this program must display Appropriate Legal Notices, as required under
30 * Section 5 of the GNU Affero General Public License version 3.
32 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
33 * these Appropriate Legal Notices must retain the display of the "Powered by
34 * SugarCRM" logo. If the display of the logo is not reasonably feasible for
35 * technical reasons, the Appropriate Legal Notices must display the words
36 * "Powered by SugarCRM".
37 ********************************************************************************/
40 require_once('modules/Import/ImportCacheFiles.php');
41 require_once('modules/Import/ImportFieldSanitize.php');
42 require_once('modules/Import/ImportDuplicateCheck.php');
48 * @var ImportFieldSanitizer
55 protected $defaultUserCurrency;
60 protected $importColumns;
65 protected $importSource;
70 protected $isUpdateOnly;
78 * @var sugarToExternalSourceFieldMap
80 protected $sugarToExternalSourceFieldMap = array();
83 public function __construct($importSource, $bean)
85 global $mod_strings, $sugar_config;
87 $this->importSource = $importSource;
89 //Vanilla copy of the bean object.
92 // use our own error handler
93 set_error_handler(array('Importer','handleImportErrors'),E_ALL);
95 // Increase the max_execution_time since this step can take awhile
96 ini_set("max_execution_time", max($sugar_config['import_max_execution_time'],3600));
99 TrackerManager::getInstance()->pause();
101 // set the default locale settings
102 $this->ifs = $this->getFieldSanitizer();
104 //Get the default user currency
105 $this->defaultUserCurrency = new Currency();
106 $this->defaultUserCurrency->retrieve('-99');
108 //Get our import column definitions
109 $this->importColumns = $this->getImportColumns();
110 $this->isUpdateOnly = ( isset($_REQUEST['import_type']) && $_REQUEST['import_type'] == 'update' );
113 public function import()
115 foreach($this->importSource as $row)
117 $this->importRow($row);
120 // save mapping if requested
121 if ( isset($_REQUEST['save_map_as']) && $_REQUEST['save_map_as'] != '' )
123 $this->saveMappingFile();
126 $this->importSource->writeStatus();
128 //All done, remove file.
132 protected function importRow($row)
134 global $sugar_config, $mod_strings, $current_user;
136 $focus = clone $this->bean;
137 $focus->unPopulateDefaultValues();
138 $focus->save_from_post = false;
139 $focus->team_id = null;
140 $this->ifs->createdBeans = array();
141 $this->importSource->resetRowErrorCounter();
144 for ( $fieldNum = 0; $fieldNum < $_REQUEST['columncount']; $fieldNum++ )
146 // loop if this column isn't set
147 if ( !isset($this->importColumns[$fieldNum]) )
150 // get this field's properties
151 $field = $this->importColumns[$fieldNum];
152 $fieldDef = $focus->getFieldDefinition($field);
153 $fieldTranslated = translate((isset($fieldDef['vname'])?$fieldDef['vname']:$fieldDef['name']), $focus->module_dir)." (".$fieldDef['name'].")";
154 $defaultRowValue = '';
155 // Bug 37241 - Don't re-import over a field we already set during the importing of another field
156 if ( !empty($focus->$field) )
163 $locale = new Localization();
165 if ( isset($row[$fieldNum]) )
167 $rowValue = $locale->translateCharset(strip_tags(trim($row[$fieldNum])),$this->importSource->importlocale_charset,$sugar_config['default_charset']);
169 else if( isset($this->sugarToExternalSourceFieldMap[$field]) && isset($row[$this->sugarToExternalSourceFieldMap[$field]]) )
171 $rowValue = $locale->translateCharset(strip_tags(trim($row[$this->sugarToExternalSourceFieldMap[$field]])),$this->importSource->importlocale_charset,$sugar_config['default_charset']);
178 // If there is an default value then use it instead
179 if ( !empty($_REQUEST[$field]) )
181 $defaultRowValue = $this->populateDefaultMapValue($field, $_REQUEST[$field], $fieldDef);
184 if( empty($rowValue))
186 $rowValue = $defaultRowValue;
187 //reset the default value to empty
192 // Bug 22705 - Don't update the First Name or Last Name value if Full Name is set
193 if ( in_array($field, array('first_name','last_name')) && !empty($focus->full_name) )
196 // loop if this value has not been set
197 if ( !isset($rowValue) )
200 // If the field is required and blank then error out
201 if ( array_key_exists($field,$focus->get_import_required_fields()) && empty($rowValue) && $rowValue!='0')
203 $this->importSource->writeError( $mod_strings['LBL_REQUIRED_VALUE'],$fieldTranslated,'NULL');
207 // Handle the special case "Sync to Outlook"
208 if ( $focus->object_name == "Contact" && $field == 'sync_contact' )
211 * Bug #41194 : if true used as value of sync_contact - add curent user to list to sync
213 if ( true == $rowValue || 'true' == strtolower($rowValue)) {
214 $focus->sync_contact = $focus->id;
215 } elseif (false == $rowValue || 'false' == strtolower($rowValue)) {
216 $focus->sync_contact = '';
218 $bad_names = array();
219 $returnValue = $this->ifs->synctooutlook($rowValue,$fieldDef,$bad_names);
220 // try the default value on fail
221 if ( !$returnValue && !empty($defaultRowValue) )
222 $returnValue = $this->ifs->synctooutlook($defaultRowValue, $fieldDef, $bad_names);
225 $this->importSource->writeError($mod_strings['LBL_ERROR_SYNC_USERS'], $fieldTranslated, $bad_names);
228 $focus->sync_contact = $returnValue;
233 // Handle email1 and email2 fields ( these don't have the type of email )
234 if ( $field == 'email1' || $field == 'email2' )
236 $returnValue = $this->ifs->email($rowValue, $fieldDef, $focus);
237 // try the default value on fail
238 if ( !$returnValue && !empty($defaultRowValue) )
239 $returnValue = $this->ifs->email( $defaultRowValue, $fieldDef);
240 if ( $returnValue === FALSE )
243 $this->importSource->writeError( $mod_strings['LBL_ERROR_INVALID_EMAIL'], $fieldTranslated, $rowValue);
247 $rowValue = $returnValue;
248 // check for current opt_out and invalid email settings for this email address
249 // if we find any, set them now
250 $emailres = $focus->db->query( "SELECT opt_out, invalid_email FROM email_addresses WHERE email_address = '".$focus->db->quote($rowValue)."'");
251 if ( $emailrow = $focus->db->fetchByAssoc($emailres) )
253 $focus->email_opt_out = $emailrow['opt_out'];
254 $focus->invalid_email = $emailrow['invalid_email'];
259 // Handle splitting Full Name into First and Last Name parts
260 if ( $field == 'full_name' && !empty($rowValue) )
262 $this->ifs->fullname($rowValue,$fieldDef,$focus);
265 // to maintain 451 compatiblity
266 if(!isset($fieldDef['module']) && $fieldDef['type']=='relate')
267 $fieldDef['module'] = ucfirst($fieldDef['table']);
269 if(isset($fieldDef['custom_type']) && !empty($fieldDef['custom_type']))
270 $fieldDef['type'] = $fieldDef['custom_type'];
272 // If the field is empty then there is no need to check the data
273 if( !empty($rowValue) )
276 $rowValue = $this->sanitizeFieldValueByType($rowValue, $fieldDef, $defaultRowValue, $focus, $fieldTranslated);
277 if ($rowValue === FALSE) {
278 /* BUG 51213 - jeff @ neposystems.com */
284 // if the parent type is in singular form, get the real module name for parent_type
285 if (isset($fieldDef['type']) && $fieldDef['type']=='parent_type') {
286 $rowValue = get_module_from_singular($rowValue);
289 $focus->$field = $rowValue;
290 unset($defaultRowValue);
293 // Now try to validate flex relate fields
294 if ( isset($focus->field_defs['parent_name']) && isset($focus->parent_name) && ($focus->field_defs['parent_name']['type'] == 'parent') )
296 // populate values from the picker widget if the import file doesn't have them
297 $parent_idField = $focus->field_defs['parent_name']['id_name'];
298 if ( empty($focus->$parent_idField) && !empty($_REQUEST[$parent_idField]) )
299 $focus->$parent_idField = $_REQUEST[$parent_idField];
301 $parent_typeField = $focus->field_defs['parent_name']['type_name'];
303 if ( empty($focus->$parent_typeField) && !empty($_REQUEST[$parent_typeField]) )
304 $focus->$parent_typeField = $_REQUEST[$parent_typeField];
306 $returnValue = $this->ifs->parent($focus->parent_name,$focus->field_defs['parent_name'],$focus, empty($_REQUEST['parent_name']));
307 if ( !$returnValue && !empty($_REQUEST['parent_name']) )
308 $returnValue = $this->ifs->parent( $_REQUEST['parent_name'],$focus->field_defs['parent_name'], $focus);
311 // check to see that the indexes being entered are unique.
312 if (isset($_REQUEST['enabled_dupes']) && $_REQUEST['enabled_dupes'] != "")
314 $toDecode = html_entity_decode ($_REQUEST['enabled_dupes'], ENT_QUOTES);
315 $enabled_dupes = json_decode($toDecode);
316 $idc = new ImportDuplicateCheck($focus);
318 if ( $idc->isADuplicateRecord($enabled_dupes) )
320 $this->importSource->markRowAsDuplicate($idc->_dupedFields);
321 $this->_undoCreatedBeans($this->ifs->createdBeans);
325 //Allow fields to be passed in for dup check as well (used by external adapters)
326 else if( !empty($_REQUEST['enabled_dup_fields']) )
328 $toDecode = html_entity_decode ($_REQUEST['enabled_dup_fields'], ENT_QUOTES);
329 $enabled_dup_fields = json_decode($toDecode);
330 $idc = new ImportDuplicateCheck($focus);
331 if ( $idc->isADuplicateRecordByFields($enabled_dup_fields) )
333 $this->importSource->markRowAsDuplicate($idc->_dupedFields);
334 $this->_undoCreatedBeans($this->ifs->createdBeans);
339 // if the id was specified
341 if ( !empty($focus->id) )
343 $focus->id = $this->_convertId($focus->id);
345 // check if it already exists
346 $query = "SELECT * FROM {$focus->table_name} WHERE id='".$focus->db->quote($focus->id)."'";
347 $result = $focus->db->query($query)
348 or sugar_die("Error selecting sugarbean: ");
350 $dbrow = $focus->db->fetchByAssoc($result);
352 if (isset ($dbrow['id']) && $dbrow['id'] != -1)
354 // if it exists but was deleted, just remove it
355 if (isset ($dbrow['deleted']) && $dbrow['deleted'] == 1 && $this->isUpdateOnly ==false)
357 $this->removeDeletedBean($focus);
358 $focus->new_with_id = true;
362 if( ! $this->isUpdateOnly )
364 $this->importSource->writeError($mod_strings['LBL_ID_EXISTS_ALREADY'],'ID',$focus->id);
365 $this->_undoCreatedBeans($this->ifs->createdBeans);
369 $clonedBean = $this->cloneExistingBean($focus);
370 if($clonedBean === FALSE)
372 $this->importSource->writeError($mod_strings['LBL_RECORD_CANNOT_BE_UPDATED'],'ID',$focus->id);
373 $this->_undoCreatedBeans($this->ifs->createdBeans);
378 $focus = $clonedBean;
385 $focus->new_with_id = true;
391 $this->saveImportBean($focus, $newRecord);
392 // Update the created/updated counter
393 $this->importSource->markRowAsImported($newRecord);
396 $this->_undoCreatedBeans($this->ifs->createdBeans);
398 unset($defaultRowValue);
403 protected function sanitizeFieldValueByType($rowValue, $fieldDef, $defaultRowValue, $focus, $fieldTranslated)
405 global $mod_strings, $app_list_strings;
406 switch ($fieldDef['type'])
410 if ( isset($fieldDef['type']) && $fieldDef['type'] == "multienum" )
411 $returnValue = $this->ifs->multienum($rowValue,$fieldDef);
413 $returnValue = $this->ifs->enum($rowValue,$fieldDef);
414 // try the default value on fail
415 if ( !$returnValue && !empty($defaultRowValue) )
417 if ( isset($fieldDef['type']) && $fieldDef['type'] == "multienum" )
418 $returnValue = $this->ifs->multienum($defaultRowValue,$fieldDef);
420 $returnValue = $this->ifs->enum($defaultRowValue,$fieldDef);
422 if ( $returnValue === FALSE )
424 $this->importSource->writeError($mod_strings['LBL_ERROR_NOT_IN_ENUM'] . implode(",",$app_list_strings[$fieldDef['options']]), $fieldTranslated,$rowValue);
433 $returnValue = $this->ifs->relate($rowValue, $fieldDef, $focus, empty($defaultRowValue));
434 if (!$returnValue && !empty($defaultRowValue))
435 $returnValue = $this->ifs->relate($defaultRowValue,$fieldDef, $focus);
436 // Bug 33623 - Set the id value found from the above method call as an importColumn
437 if ($returnValue !== false)
438 $this->importColumns[] = $fieldDef['id_name'];
442 $this->ifs->teamset($rowValue,$fieldDef,$focus);
443 $this->importColumns[] = 'team_set_id';
444 $this->importColumns[] = 'team_id';
451 $fieldtype = $fieldDef['type'];
452 $returnValue = $this->ifs->$fieldtype($rowValue, $fieldDef, $focus);
453 // try the default value on fail
454 if ( !$returnValue && !empty($defaultRowValue) )
455 $returnValue = $this->ifs->$fieldtype($defaultRowValue,$fieldDef, $focus);
458 $this->importSource->writeError($mod_strings['LBL_ERROR_INVALID_'.strtoupper($fieldDef['type'])],$fieldTranslated,$rowValue,$focus);
465 protected function cloneExistingBean($focus)
467 $existing_focus = clone $this->bean;
468 if ( !( $existing_focus->retrieve($focus->id) instanceOf SugarBean ) )
474 $newData = $focus->toArray();
475 foreach ( $newData as $focus_key => $focus_value )
476 if ( in_array($focus_key,$this->importColumns) )
477 $existing_focus->$focus_key = $focus_value;
479 return $existing_focus;
483 protected function removeDeletedBean($focus)
487 $query2 = "DELETE FROM {$focus->table_name} WHERE id='".$focus->db->quote($focus->id)."'";
488 $result2 = $focus->db->query($query2) or sugar_die($mod_strings['LBL_ERROR_DELETING_RECORD']." ".$focus->id);
489 if ($focus->hasCustomFields())
491 $query3 = "DELETE FROM {$focus->table_name}_cstm WHERE id_c='".$focus->db->quote($focus->id)."'";
492 $result2 = $focus->db->query($query3);
496 protected function saveImportBean($focus, $newRecord)
498 global $timedate, $current_user;
500 // Populate in any default values to the bean
501 $focus->populateDefaultValues();
503 if ( !isset($focus->assigned_user_id) || $focus->assigned_user_id == '' && $newRecord )
505 $focus->assigned_user_id = $current_user->id;
508 * Bug 34854: Added all conditions besides the empty check on date modified.
510 if ( ( !empty($focus->new_with_id) && !empty($focus->date_modified) ) ||
511 ( empty($focus->new_with_id) && $timedate->to_db($focus->date_modified) != $timedate->to_db($timedate->to_display_date_time($focus->fetched_row['date_modified'])) )
513 $focus->update_date_modified = false;
515 $focus->optimistic_lock = false;
516 if ( $focus->object_name == "Contact" && isset($focus->sync_contact) )
518 //copy the potential sync list to another varible
519 $list_of_users=$focus->sync_contact;
520 //and set it to false for the save
521 $focus->sync_contact=false;
523 else if($focus->object_name == "User" && !empty($current_user) && $focus->is_admin && !is_admin($current_user) && is_admin_for_module($current_user, 'Users')) {
524 sugar_die($GLOBALS['mod_strings']['ERR_IMPORT_SYSTEM_ADMININSTRATOR']);
526 //bug# 46411 importing Calls will not populate Leads or Contacts Subpanel
527 if (!empty($focus->parent_type) && !empty($focus->parent_id))
529 foreach ($focus->relationship_fields as $key => $val)
531 if ($val == strtolower($focus->parent_type))
533 $focus->$key = $focus->parent_id;
537 //bug# 40260 setting it true as the module in focus is involved in an import
538 $focus->in_import=true;
539 // call any logic needed for the module preSave
540 $focus->beforeImportSave();
542 // if modified_user_id is set, set the flag to false so SugarBEan will not reset it
543 if (isset($focus->modified_user_id) && $focus->modified_user_id) {
544 $focus->update_modified_by = false;
546 // if created_by is set, set the flag to false so SugarBEan will not reset it
547 if (isset($focus->created_by) && $focus->created_by) {
548 $focus->set_created_by = false;
551 if ( $focus->object_name == "Contact" && isset($list_of_users) )
552 $focus->process_sync_to_outlook($list_of_users);
556 //now that save is done, let's make sure that parent and related id's were saved as relationships
557 //this takes place before the afterImportSave()
558 $this->checkRelatedIDsAfterSave($focus);
560 // call any logic needed for the module postSave
561 $focus->afterImportSave();
563 // Add ID to User's Last Import records
565 $this->importSource->writeRowToLastImport( $_REQUEST['import_module'],($focus->object_name == 'Case' ? 'aCase' : $focus->object_name),$focus->id);
569 protected function saveMappingFile()
571 global $current_user;
573 $firstrow = unserialize(base64_decode($_REQUEST['firstrow']));
574 $mappingValsArr = $this->importColumns;
575 $mapping_file = new ImportMap();
576 if ( isset($_REQUEST['has_header']) && $_REQUEST['has_header'] == 'on')
578 $header_to_field = array ();
579 foreach ($this->importColumns as $pos => $field_name)
581 if (isset($firstrow[$pos]) && isset($field_name))
583 $header_to_field[$firstrow[$pos]] = $field_name;
587 $mappingValsArr = $header_to_field;
589 //get array of values to save for duplicate and locale settings
590 $advMapping = $this->retrieveAdvancedMapping();
592 //merge with mappingVals array
593 if(!empty($advMapping) && is_array($advMapping))
595 $mappingValsArr = array_merge($mappingValsArr,$advMapping);
599 $mapping_file->setMapping($mappingValsArr);
601 // save default fields
602 $defaultValues = array();
603 for ( $i = 0; $i < $_REQUEST['columncount']; $i++ )
605 if (isset($this->importColumns[$i]) && !empty($_REQUEST[$this->importColumns[$i]]))
607 $field = $this->importColumns[$i];
608 $fieldDef = $this->bean->getFieldDefinition($field);
609 if(!empty($fieldDef['custom_type']) && $fieldDef['custom_type'] == 'teamset')
611 require_once('include/SugarFields/Fields/Teamset/SugarFieldTeamset.php');
612 $sugar_field = new SugarFieldTeamset('Teamset');
613 $teams = $sugar_field->getTeamsFromRequest($field);
614 if(isset($_REQUEST['primary_team_name_collection']))
616 $primary_index = $_REQUEST['primary_team_name_collection'];
619 //If primary_index was selected, ensure that the first Array entry is the primary team
620 if(isset($primary_index))
623 $new_teams = array();
624 foreach($teams as $id=>$name)
626 if($primary_index == $count++)
628 $new_teams[$id] = $name;
634 foreach($teams as $id=>$name)
636 $new_teams[$id] = $name;
641 $json = getJSONobj();
642 $defaultValues[$field] = $json->encode($teams);
646 $defaultValues[$field] = $_REQUEST[$this->importColumns[$i]];
650 $mapping_file->setDefaultValues($defaultValues);
651 $result = $mapping_file->save( $current_user->id, $_REQUEST['save_map_as'], $_REQUEST['import_module'], $_REQUEST['source'],
652 ( isset($_REQUEST['has_header']) && $_REQUEST['has_header'] == 'on'), $_REQUEST['custom_delimiter'], html_entity_decode($_REQUEST['custom_enclosure'],ENT_QUOTES)
657 protected function populateDefaultMapValue($field, $fieldValue, $fieldDef)
659 global $timedate, $current_user;
661 if ( is_array($fieldValue) )
662 $defaultRowValue = encodeMultienumValue($fieldValue);
664 $defaultRowValue = $_REQUEST[$field];
665 // translate default values to the date/time format for the import file
666 if( $fieldDef['type'] == 'date' && $this->ifs->dateformat != $timedate->get_date_format() )
667 $defaultRowValue = $timedate->swap_formats($defaultRowValue, $this->ifs->dateformat, $timedate->get_date_format());
669 if( $fieldDef['type'] == 'time' && $this->ifs->timeformat != $timedate->get_time_format() )
670 $defaultRowValue = $timedate->swap_formats($defaultRowValue, $this->ifs->timeformat, $timedate->get_time_format());
672 if( ($fieldDef['type'] == 'datetime' || $fieldDef['type'] == 'datetimecombo') && $this->ifs->dateformat.' '.$this->ifs->timeformat != $timedate->get_date_time_format() )
673 $defaultRowValue = $timedate->swap_formats($defaultRowValue, $this->ifs->dateformat.' '.$this->ifs->timeformat,$timedate->get_date_time_format());
675 if ( in_array($fieldDef['type'],array('currency','float','int','num')) && $this->ifs->num_grp_sep != $current_user->getPreference('num_grp_sep') )
676 $defaultRowValue = str_replace($current_user->getPreference('num_grp_sep'), $this->ifs->num_grp_sep,$defaultRowValue);
678 if ( in_array($fieldDef['type'],array('currency','float')) && $this->ifs->dec_sep != $current_user->getPreference('dec_sep') )
679 $defaultRowValue = str_replace($current_user->getPreference('dec_sep'), $this->ifs->dec_sep,$defaultRowValue);
681 $user_currency_symbol = $this->defaultUserCurrency->symbol;
682 if ( $fieldDef['type'] == 'currency' && $this->ifs->currency_symbol != $user_currency_symbol )
683 $defaultRowValue = str_replace($user_currency_symbol, $this->ifs->currency_symbol,$defaultRowValue);
685 return $defaultRowValue;
688 protected function getImportColumns()
690 $importable_fields = $this->bean->get_importable_fields();
691 $importColumns = array();
692 foreach ($_REQUEST as $name => $value)
694 // only look for var names that start with "fieldNum"
695 if (strncasecmp($name, "colnum_", 7) != 0)
698 // pull out the column position for this field name
699 $pos = substr($name, 7);
701 if ( isset($importable_fields[$value]) )
703 // now mark that we've seen this field
704 $importColumns[$pos] = $value;
708 return $importColumns;
711 protected function getFieldSanitizer()
713 $ifs = new ImportFieldSanitize();
714 $copyFields = array('dateformat','timeformat','timezone','default_currency_significant_digits','num_grp_sep','dec_sep','default_locale_name_format');
715 foreach($copyFields as $field)
717 $fieldKey = "importlocale_$field";
718 $ifs->$field = $this->importSource->$fieldKey;
721 $currency = new Currency();
722 $currency->retrieve($this->importSource->importlocale_currency);
723 $ifs->currency_symbol = $currency->symbol;
729 * Sets a translation map from sugar field key to external source key used while importing a row. This allows external sources
730 * to return a data set that is an associative array rather than numerically indexed.
735 public function setFieldKeyTranslator($translator)
737 $this->sugarToExternalSourceFieldMap = $translator;
741 * If a bean save is not done for some reason, this method will undo any of the beans that were created
743 * @param array $ids ids of user_last_import records created
745 protected function _undoCreatedBeans( array $ids )
747 $focus = new UsersLastImport();
748 foreach ($ids as $id)
749 $focus->undoById($id);
753 * clean id's when being imported
755 * @param string $string
758 protected function _convertId($string)
760 return preg_replace_callback(
761 '|[^A-Za-z0-9\-\_]|',
763 // single quotes are essential here,
764 // or alternative escape all $ as \$
766 'return ord($matches[0]);'
771 public function retrieveAdvancedMapping()
773 $advancedMappingSettings = array();
775 //harvest the dupe index settings
776 if( isset($_REQUEST['enabled_dupes']) )
778 $toDecode = html_entity_decode ($_REQUEST['enabled_dupes'], ENT_QUOTES);
779 $dupe_ind = json_decode($toDecode);
781 foreach($dupe_ind as $dupe)
783 $advancedMappingSettings['dupe_'.$dupe] = $dupe;
787 foreach($_REQUEST as $rk=>$rv)
789 //harvest the import locale settings
790 if(strpos($rk,'portlocale_')>0)
792 $advancedMappingSettings[$rk] = $rv;
796 return $advancedMappingSettings;
799 public static function getImportableModules()
802 $importableModules = array();
803 foreach ($beanList as $moduleName => $beanName)
805 if( class_exists($beanName) )
807 $tmp = new $beanName();
808 if( isset($tmp->importable) && $tmp->importable )
810 $label = isset($GLOBALS['app_list_strings']['moduleList'][$moduleName]) ? $GLOBALS['app_list_strings']['moduleList'][$moduleName] : $moduleName;
811 $importableModules[$moduleName] = $label;
816 asort($importableModules);
817 return $importableModules;
822 * Replaces PHP error handler in Step4
825 * @param string $errstr
826 * @param string $errfile
827 * @param string $errline
829 public static function handleImportErrors($errno, $errstr, $errfile, $errline)
831 $GLOBALS['log']->fatal("Caught error: $errstr");
833 if ( !defined('E_DEPRECATED') )
834 define('E_DEPRECATED','8192');
835 if ( !defined('E_USER_DEPRECATED') )
836 define('E_USER_DEPRECATED','16384');
842 $message = "ERROR: [$errno] $errstr on line $errline in file $errfile<br />\n";
847 $message = "WARNING: [$errno] $errstr on line $errline in file $errfile<br />\n";
851 $message = "NOTICE: [$errno] $errstr on line $errline in file $errfile<br />\n";
855 case E_USER_DEPRECATED:
856 // don't worry about these
857 // $message = "STRICT ERROR: [$errno] $errstr on line $errline in file $errfile<br />\n";
861 $message = "Unknown error type: [$errno] $errstr on line $errline in file $errfile<br />\n";
865 // check to see if current reporting level should be included based upon error_reporting() setting, if not
867 if (error_reporting() & $errno)
880 * upon bean save, the relationships are saved by SugarBean->save_relationship_changes() method, but those values depend on
881 * the request object and is not reliable during import. This function makes sure any defined related or parent id's are processed
882 * and their relationship saved.
884 public function checkRelatedIDsAfterSave($focus)
890 //check relationship fields first
891 if(!empty($focus->parent_id) && !empty($focus->parent_type)){
892 $relParentName = strtolower($focus->parent_type);
893 $relParentID = strtolower($focus->parent_id);
895 if(!empty($focus->related_id) && !empty($focus->related_type)){
896 $relName = strtolower($focus->related_type);
897 $relID = strtolower($focus->related_id);
900 //now refresh the bean and process for parent relationship
901 $focus->retrieve($focus->id);
902 if(!empty($relParentName) && !empty($relParentID)){
904 //grab the relationship and any available ids
905 if(!empty($focus->$relParentName)){
907 $focus->load_relationship($relParentName);
908 $rel_ids = $focus->$relParentName->get();
910 //if the current parent_id is not part of the stored rels, then add it
911 if(!in_array($relParentID, $rel_ids)){
912 $focus->$relParentName->add($relParentID);
917 //now lets process any related fields
918 if(!empty($relName) && !empty($relID)){
919 if(!empty($focus->$relName)){
921 $focus->load_relationship($relName);
922 $rel_ids = $focus->$relName->get();
924 //if the related_id is not part of the stored rels, then add it
925 if(!in_array($relID, $rel_ids)){
926 $focus->$relName->add($relID);