Index: trunk/core/units/general/cat_dbitem_export.php =================================================================== diff -u -N --- trunk/core/units/general/cat_dbitem_export.php (revision 7855) +++ trunk/core/units/general/cat_dbitem_export.php (revision 0) @@ -1,1388 +0,0 @@ -cacheTable = TABLE_PREFIX.'ImportCache'; - } - - /** - * Returns value from cache if found or false otherwise - * - * @param string $type - * @param int $key - * @return mixed - */ - function getFromCache($type, $key) - { - return getArrayValue($this->cache, $type, $key); - } - - /** - * Adds value to be cached - * - * @param string $type - * @param int $key - * @param mixed $value - */ - function addToCache($type, $key, $value, $is_new = true) - { -// if (!isset($this->cache[$type])) $this->cache[$type] = Array(); - $this->cache[$type][$key] = $value; - if ($is_new) { - $this->cacheStatus[$type][$key] = true; - } - } - - function storeCache($cache_types) - { - $cache_types = explode(',', $cache_types); - - $values_sql = ''; - foreach ($cache_types as $cache_type) { - $sql_mask = '('.$this->Conn->qstr($cache_type).',%s,%s),'; - $cache = getArrayValue($this->cacheStatus, $cache_type); - if (!$cache) $cache = Array(); - foreach ($cache as $var_name => $cache_status) { - $var_value = $this->cache[$cache_type][$var_name]; - $values_sql .= sprintf($sql_mask, $this->Conn->qstr($var_name), $this->Conn->qstr($var_value) ); - } - } - $values_sql = preg_replace('/(.*),$/', '\\1', $values_sql); - if ($values_sql) { - $sql = 'INSERT INTO '.$this->cacheTable.'(`CacheName`,`VarName`,`VarValue`) VALUES '.$values_sql; - $this->Conn->Query($sql); - } - - } - - function loadCache() - { - $sql = 'SELECT * FROM '.$this->cacheTable; - $records = $this->Conn->Query($sql); - - $this->cache = Array(); - foreach ($records as $record) { - $this->addToCache($record['CacheName'], $record['VarName'], $record['VarValue'], false); - } - } - - /** - * Fill required fields with dummy values - * - * @param kEvent $event - */ - function fillRequiredFields(&$event, &$object, $set_status = false) - { - if ($object == $this->false) { - $object =& $event->getObject(); - } - - $has_empty = false; - $fields = array_keys($object->Fields); - foreach ($fields as $field_name) - { - $field_options =& $object->Fields[$field_name]; - if (isset($object->VirtualFields[$field_name]) || !getArrayValue($field_options, 'required') ) continue; - if ( $object->GetDBField($field_name) ) continue; - - $formatter_class = getArrayValue($field_options, 'formatter'); - if ($formatter_class) // not tested - { - $formatter =& $this->Application->recallObject($formatter_class); - $sample_value = $formatter->GetSample($field_name, $field_options, $object); - } - - $has_empty = true; - $object->SetField($field_name, isset($sample_value) && $sample_value ? $sample_value : 'no value'); - } - $object->UpdateFormattersSubFields(); - - if ($set_status && $has_empty) { - $object->SetDBField('Status', 0); - } - } - - /** - * Verifies that all user entered export params are correct - * - * @param kEvent $event - */ - function verifyOptions(&$event) - { - if ($this->Application->RecallVar($event->getPrefixSpecial().'_ForceNotValid')) - { - $this->Application->StoreVar($event->getPrefixSpecial().'_ForceNotValid', 0); - return false; - } - - $this->fillRequiredFields($event, $this->false); - - $object =& $event->getObject(); - $cross_unique_fields = Array('FieldsSeparatedBy', 'FieldsEnclosedBy'); - if (($object->GetDBField('CategoryFormat') == 1) || ($event->Special == 'import')) // in one field - { - $object->setRequired('CategorySeparator', true); - $cross_unique_fields[] = 'CategorySeparator'; - } - - $ret = $object->Validate(); - - // check if cross unique fields has no same values - foreach ($cross_unique_fields as $field_index => $field_name) - { - if (getArrayValue($object->FieldErrors, $field_name, 'pseudo') == 'required') continue; - - $check_fields = $cross_unique_fields; - unset($check_fields[$field_index]); - - foreach ($check_fields as $check_field) - { - if ($object->GetDBField($field_name) == $object->GetDBField($check_field)) - { - $object->SetError($check_field, 'unique'); - } - } - } - - if ($event->Special == 'import') - { - $this->exportOptions = $this->loadOptions($event); - - $automatic_fields = ($object->GetDBField('FieldTitles') == 1); - $object->setRequired('ExportColumns', !$automatic_fields); - $category_prefix = '__CATEGORY__'; - if ( $automatic_fields && ($this->exportOptions['SkipFirstRow']) ) { - $this->openFile($event); - $this->exportOptions['ExportColumns'] = $this->readRecord(); - $this->closeFile(); - - // remove additional (non-parseble columns) - foreach ($this->exportOptions['ExportColumns'] as $field_index => $field_name) { - if (!$this->validateField($field_name, $object)) { - unset($this->exportOptions['ExportColumns'][$field_index]); - } - } - $category_prefix = ''; - } - - // 1. check, that we have column definitions - if (!$this->exportOptions['ExportColumns']) { - $object->setError('ExportColumns', 'required'); - $ret = false; - } - else { - // 1.1. check that all required fields are present in imported file - $missing_columns = Array(); - foreach ($object->Fields as $field_name => $field_options) { - if ($object->SkipField($field_name)) continue; - if (getArrayValue($field_options, 'required') && !in_array($field_name, $this->exportOptions['ExportColumns']) ) { - $missing_columns[] = $field_name; - $object->setError('ExportColumns', 'required_fields_missing', 'la_error_RequiredColumnsMissing'); - $ret = false; - } - } - - if (!$ret && $this->Application->isDebugMode()) { - $this->Application->Debugger->appendHTML('Missing required for import/export:'); - $this->Application->Debugger->dumpVars($missing_columns); - } - } - - - // 2. check, that we have only mixed category field or only separated category fields - $category_found['mixed'] = false; - $category_found['separated'] = false; - - foreach ($this->exportOptions['ExportColumns'] as $import_field) { - if (preg_match('/^'.$category_prefix.'Category(Path|[0-9]+)/', $import_field, $rets)) { - $category_found[$rets[1] == 'Path' ? 'mixed' : 'separated'] = true; - } - } - if ($category_found['mixed'] && $category_found['separated']) { - $object->SetError('ExportColumns', 'unique_category', 'la_error_unique_category_field'); - $ret = false; - } - - // 3. check, that duplicates check fields are selected & present in imported fields - if ($this->exportOptions['ReplaceDuplicates']) { - if ($this->exportOptions['CheckDuplicatesMethod'] == 1) { - $check_fields = Array($object->IDField); - } - else { - $check_fields = $this->exportOptions['DuplicateCheckFields'] ? explode('|', substr($this->exportOptions['DuplicateCheckFields'], 1, -1)) : Array(); - $object =& $event->getObject(); - - $language_id = $this->Application->GetDefaultLanguageId(); - foreach ($check_fields as $index => $check_field) { - foreach ($object->Fields as $field_name => $field_options) { - if ($field_name == 'l'.$language_id.'_'.$check_field) { - $check_fields[$index] = 'l'.$language_id.'_'.$check_field; - break; - } - } - } - } - $this->exportOptions['DuplicateCheckFields'] = $check_fields; - - if (!$check_fields) { - $object->setError('CheckDuplicatesMethod', 'required'); - $ret = false; - } - else { - foreach ($check_fields as $check_field) { - $check_field = preg_replace('/^cust_(.*)/', 'Custom_\\1', $check_field); - if (!in_array($check_field, $this->exportOptions['ExportColumns'])) { - $object->setError('ExportColumns', 'required'); - $ret = false; - break; - } - } - } - } - $this->saveOptions($event); - } - - return $ret; - } - - /** - * Returns filename to read import data from - * - * @return string - */ - function getImportFilename() - { - if ($this->exportOptions['ImportSource'] == 1) - { - $ret = $this->exportOptions['ImportFilename']; // ['name']; commented by Kostja - } - else { - $ret = $this->exportOptions['ImportLocalFilename']; - } - return EXPORT_PATH.'/'.$ret; - } - - /** - * Returns filename to write export data to - * - * @return string - */ - function getExportFilename() - { - return EXPORT_PATH.'/'.$this->exportOptions['ExportFilename'].'.'.$this->getFileExtension(); - } - - /** - * Opens file required for export/import operations - * - * @param kEvent $event - */ - function openFile(&$event) - { - if ($event->Special == 'export') { - $write_mode = ($this->exportOptions['start_from'] == 0) ? 'w' : 'a'; - $this->filePointer = fopen($this->getExportFilename(), $write_mode); - } - else { - $this->filePointer = fopen($this->getImportFilename(), 'r'); - } - - // skip UTF-8 BOM Modifier - $first_chars = fread($this->filePointer, 3); - if (bin2hex($first_chars) != 'efbbbf') { - fseek($this->filePointer, 0); - } - } - - /** - * Closes opened file - * - */ - function closeFile() - { - fclose($this->filePointer); - } - - function getCustomSQL() - { - $ml_formatter =& $this->Application->recallObject('kMultiLanguage'); - - $custom_sql = ''; - foreach ($this->customFields as $custom_id => $custom_name) { - $custom_sql .= 'custom_data.'.$ml_formatter->LangFieldName('cust_'.$custom_id).' AS cust_'.$custom_name.', '; - } - - return preg_replace('/(.*), /', '\\1', $custom_sql); - } - - function getPlainExportSQL($count_only = false) { - if ($count_only && isset($this->exportOptions['ForceCountSQL'])) { - $sql = $this->exportOptions['ForceCountSQL']; - } - elseif (!$count_only && isset($this->exportOptions['ForceSelectSQL'])) { - $sql = $this->exportOptions['ForceSelectSQL']; - } - else { - $items_list =& $this->Application->recallObject($this->curItem->Prefix.'.export-items-list', $this->curItem->Prefix.'_List'); - $items_list->SetPerPage(-1); - - if ($options['export_ids'] != '') { - $items_list->AddFilter('export_ids', $items_list->TableName.'.'.$items_list->IDField.' IN ('.implode(',',$options['export_ids']).')'); - } - - if ($count_only) { - $sql = $items_list->getCountSQL( $items_list->GetSelectSQL(true,false) ); - } - else { - $sql = $items_list->GetSelectSQL(); - } - } - - if (!$count_only) - { - $sql .= ' LIMIT '.$this->exportOptions['start_from'].','.EXPORT_STEP; - } -// else { -// $sql = preg_replace("/^.*SELECT(.*?)FROM(?!_)/is", "SELECT COUNT(*) AS count FROM ", $sql); -// } - - return $sql; - } - - function getExportSQL($count_only = false) - { - if (!$this->Application->getUnitOption($this->curItem->Prefix, 'CatalogItem')) { - return $this->GetPlainExportSQL($count_only); // in case this is not a CategoryItem - } - - if ($this->exportOptions['export_ids'] === false) - { - // get links from current category & all it's subcategories - $join_clauses = Array(); - - $custom_sql = $this->getCustomSQL(); - if ($custom_sql) { - $custom_table = $this->Application->getUnitOption($this->curItem->Prefix.'-cdata', 'TableName'); - $join_clauses[$custom_table.' custom_data'] = 'custom_data.ResourceId = item_table.ResourceId'; - } - - $join_clauses[TABLE_PREFIX.'CategoryItems ci'] = 'ci.ItemResourceId = item_table.ResourceId'; - $join_clauses[TABLE_PREFIX.'Category c'] = 'c.CategoryId = ci.CategoryId'; - - $sql = 'SELECT item_table.*, ci.CategoryId'.($custom_sql ? ', '.$custom_sql : '').' - FROM '.$this->curItem->TableName.' item_table'; - - foreach ($join_clauses as $table_name => $join_expression) { - $sql .= ' LEFT JOIN '.$table_name.' ON '.$join_expression; - } - $sql .= ' WHERE '; - - if ($this->exportOptions['export_cats_ids'][0] == 0) - { - $sql .= '1'; - } - else { - foreach ($this->exportOptions['export_cats_ids'] as $category_id) { - $sql .= '(c.ParentPath LIKE "%|'.$category_id.'|%") OR '; - } - $sql = preg_replace('/(.*) OR $/', '\\1', $sql); - } - - $sql .= ' ORDER BY ci.PrimaryCat DESC'; // NEW - } - else { - // get only selected links - $sql = 'SELECT item_table.*, '.$this->exportOptions['export_cats_ids'][0].' AS CategoryId - FROM '.$this->curItem->TableName.' item_table - WHERE '.$this->curItem->IDField.' IN ('.implode(',', $this->exportOptions['export_ids']).')'; - } - - if (!$count_only) - { - $sql .= ' LIMIT '.$this->exportOptions['start_from'].','.EXPORT_STEP; - } - else { - $sql = preg_replace("/^.*SELECT(.*?)FROM(?!_)/is", "SELECT COUNT(*) AS count FROM ", $sql); - } - - return $sql; - } - - /** - * Enter description here... - * - * @param kEvent $event - */ - function performExport(&$event) - { - $this->exportOptions = $this->loadOptions($event); - $this->exportFields = $this->exportOptions['ExportColumns']; - $this->curItem =& $event->getObject( Array('skip_autoload' => true) ); - $this->customFields = $this->Application->getUnitOption($event->Prefix, 'CustomFields'); - $this->openFile($event); - - if ($this->exportOptions['start_from'] == 0) // first export step - { - if (!getArrayValue($this->exportOptions, 'IsBaseCategory')) { - $this->exportOptions['IsBaseCategory'] = 0; - } - - if ($this->exportOptions['IsBaseCategory'] ) { - $sql = 'SELECT ParentPath - FROM '.TABLE_PREFIX.'Category - WHERE CategoryId = '.$this->Application->GetVar('m_cat_id'); - $this->exportOptions['BaseLevel'] = substr_count($this->Conn->GetOne($sql), '|') - 1; // level to cut from other categories - } - - // 1. export field titles if required - if ($this->exportOptions['IncludeFieldTitles']) - { - $data_array = Array(); - foreach ($this->exportFields as $export_field) - { - $data_array = array_merge($data_array, $this->getFieldCaption($export_field)); - } - $this->writeRecord($data_array); - } - $this->exportOptions['total_records'] = $this->Conn->GetOne( $this->getExportSQL(true) ); - } - - // 2. export data - $records = $this->Conn->Query( $this->getExportSQL() ); - $records_exported = 0; - foreach ($records as $record_info) { - $this->curItem->Clear(); - $this->curItem->SetDBFieldsFromHash($record_info); - $this->setCurrentID(); - $this->curItem->raiseEvent('OnAfterItemLoad', $this->curItem->GetID() ); - - $data_array = Array(); - foreach ($this->exportFields as $export_field) - { - $data_array = array_merge($data_array, $this->getFieldValue($export_field) ); - } - $this->writeRecord($data_array); - $records_exported++; - } - $this->closeFile(); - - $this->exportOptions['start_from'] += $records_exported; - $this->saveOptions($event); - - return $this->exportOptions; - } - - function getItemFields() - { - // just in case dummy user selected automtic mode & moved columns too :( - return array_merge($this->curItem->Fields['AvailableColumns']['options'], $this->curItem->Fields['ExportColumns']['options']); - } - - /** - * Checks if field really belongs to importable field list - * - * @param string $field_name - * @param kCatDBItem $object - * @return bool - */ - function validateField($field_name, &$object) - { - // 1. convert custom field - $field_name = preg_replace('/^Custom_(.*)/', '__CUSTOM__\\1', $field_name); - - // 2. convert category field (mixed version & serparated version) - $field_name = preg_replace('/^Category(Path|[0-9]+)/', '__CATEGORY__Category\\1', $field_name); - - $valid_fields = $object->getPossibleExportColumns(); - return isset($valid_fields[$field_name]) || isset($valid_fields['__VIRTUAL__'.$field_name]); - } - - /** - * Enter description here... - * - * @param kEvent $event - */ - function performImport(&$event) - { - if (!$this->exportOptions) { - // load import options in case if not previously loaded in verification function - $this->exportOptions = $this->loadOptions($event); - } - - $backup_category_id = $this->Application->GetVar('m_cat_id'); - $this->Application->SetVar('m_cat_id', (int)$this->Application->RecallVar('ImportCategory') ); - - $this->openFile($event); - - $bytes_imported = 0; - if ($this->exportOptions['start_from'] == 0) // first export step - { - // 1st time run - if ($this->exportOptions['SkipFirstRow']) { - $this->readRecord(); - $this->exportOptions['start_from'] = ftell($this->filePointer); - $bytes_imported = ftell($this->filePointer); - } - - $current_category_id = $this->Application->GetVar('m_cat_id'); - if ($current_category_id > 0) { - $sql = 'SELECT ParentPath FROM '.TABLE_PREFIX.'Category WHERE CategoryId = '.$current_category_id; - $this->exportOptions['ImportCategoryPath'] = $this->Conn->GetOne($sql); - } - else { - $this->exportOptions['ImportCategoryPath'] = ''; - } - $this->exportOptions['total_records'] = filesize($this->getImportFilename()); - } - else { - $this->loadCache(); - } - - $this->exportFields = $this->exportOptions['ExportColumns']; - $this->addToCache('category_parent_path', $this->Application->GetVar('m_cat_id'), $this->exportOptions['ImportCategoryPath']); - - // 2. import data - $this->dummyCategory =& $this->Application->recallObject('c.-tmpitem', 'c', Array('skip_autoload' => true)); - fseek($this->filePointer, $this->exportOptions['start_from']); - - $items_processed = 0; - while (($bytes_imported < IMPORT_CHUNK && $items_processed < IMPORT_STEP) && !feof($this->filePointer)) { - $data = $this->readRecord(); - if ($data) { - if ($this->exportOptions['ReplaceDuplicates']) { - // set fields used as keys for replace duplicates code - $this->resetImportObject($event, IMPORT_TEMP, $data); - } - - $this->processCurrentItem($event, $data); - } - $bytes_imported = ftell($this->filePointer) - $this->exportOptions['start_from']; - $items_processed++; - } - - $this->closeFile(); - $this->Application->SetVar('m_cat_id', $backup_category_id); - - $this->exportOptions['start_from'] += $bytes_imported; - $this->storeCache('new_ids'); - - $this->saveOptions($event); - - if ($this->exportOptions['start_from'] == $this->exportOptions['total_records']) { - $this->Conn->Query('TRUNCATE TABLE '.$this->cacheTable); - } - - return $this->exportOptions; - } - - function setCurrentID() - { - $this->curItem->setID( $this->curItem->GetDBField($this->curItem->IDField) ); - } - - function setFieldValue($field_index, $value) - { - if (empty($value)) { - $value = null; - } - - $field_name = getArrayValue($this->exportFields, $field_index); - if ($field_name == 'ResourceId') { - return false; - } - - if (substr($field_name, 0, 7) == 'Custom_') { - $field_name = 'cust_'.substr($field_name, 7); - $this->curItem->SetField($field_name, $value); - } - elseif ($field_name == 'CategoryPath' || $field_name == '__CATEGORY__CategoryPath') { - $this->curItem->CategoryPath = $value ? explode($this->exportOptions['CategorySeparator'], $value) : Array(); - } - elseif (substr($field_name, 0, 8) == 'Category') { - $this->curItem->CategoryPath[ (int)substr($field_name, 8) - 1 ] = $value; - } - elseif (substr($field_name, 0, 20) == '__CATEGORY__Category') { - $this->curItem->CategoryPath[ (int)substr($field_name, 20) ] = $value; - } - elseif (substr($field_name, 0, 11) == '__VIRTUAL__') { - $field_name = substr($field_name, 11); - $this->curItem->SetField($field_name, $value); - } - else { - $this->curItem->SetField($field_name, $value); - } - - $pseudo_error = getArrayValue($this->curItem->FieldErrors, $field_name, 'pseudo'); - if ($pseudo_error) { - $this->curItem->SetDBField($field_name, null); - unset($this->curItem->FieldErrors[$field_name]); - } - } - - function resetImportObject(&$event, $object_type, $record_data = null) - { - switch ($object_type) { - case IMPORT_TEMP: - $this->curItem =& $event->getObject( Array('skip_autoload' => true) ); - break; - - case IMPORT_LIVE: - $this->curItem =& $this->Application->recallObject($event->Prefix.'.-tmpitem'.$event->Special, $event->Prefix, Array('skip_autoload' => true)); - break; - } - $this->curItem->Clear(); - $this->customFields = $this->Application->getUnitOption($event->Prefix, 'CustomFields'); - - if (isset($record_data)) { - $this->setImportData($record_data); - } - } - - function setImportData($record_data) - { - foreach ($record_data as $field_index => $field_value) { - $this->setFieldValue($field_index, $field_value); - } - $this->setCurrentID(); - } - - - function getItemCategory() - { - static $lang_prefix = null; - $backup_category_id = $this->Application->GetVar('m_cat_id'); - - $category_id = $this->getFromCache('category_names', implode(':', $this->curItem->CategoryPath)); - if ($category_id) { - $this->Application->SetVar('m_cat_id', $category_id); - return $category_id; - } - - if (is_null($lang_prefix)) { - $lang_prefix = 'l'.$this->Application->GetVar('m_lang').'_'; - } - - foreach ($this->curItem->CategoryPath as $category_index => $category_name) { - if (!$category_name) continue; - $category_key = crc32( implode(':', array_slice($this->curItem->CategoryPath, 0, $category_index + 1) ) ); - - $category_id = $this->getFromCache('category_names', $category_key); - if ($category_id === false) { - // get parent category path to search only in it - $current_category_id = $this->Application->GetVar('m_cat_id'); -// $parent_path = $this->getParentPath($current_category_id); - - // get category id from database by name - $sql = 'SELECT CategoryId - FROM '.TABLE_PREFIX.'Category - WHERE ('.$lang_prefix.'Name = '.$this->Conn->qstr($category_name).') AND (ParentId = '.$current_category_id.')'; - $category_id = $this->Conn->GetOne($sql); - - if ($category_id === false) { - // category not in db -> create - $category_fields = Array( $lang_prefix.'Name' => $category_name, $lang_prefix.'Description' => $category_name, - 'Status' => STATUS_ACTIVE, 'ParentId' => $current_category_id, 'AutomaticFilename' => 1 - ); - $this->dummyCategory->SetDBFieldsFromHash($category_fields); - if ($this->dummyCategory->Create()) { - $category_id = $this->dummyCategory->GetID(); - $this->addToCache('category_parent_path', $category_id, $this->dummyCategory->GetDBField('ParentPath')); - $this->addToCache('category_names', $category_key, $category_id); - } - } - else { - $this->addToCache('category_names', $category_key, $category_id); - } - } - - if ($category_id) { - $this->Application->SetVar('m_cat_id', $category_id); - } - } - if (!$this->curItem->CategoryPath) { - $category_id = $backup_category_id; - } - - return $category_id; - } - - /** - * Enter description here... - * - * @param kEvent $event - */ - function processCurrentItem(&$event, $record_data) - { - $save_method = 'Create'; - $load_keys = Array(); - - // create/update categories - $backup_category_id = $this->Application->GetVar('m_cat_id'); - - // perform replace duplicates code - if ($this->exportOptions['ReplaceDuplicates']) { - // get replace keys first, then reset current item to empty one - $category_id = $this->getItemCategory(); - if ($this->exportOptions['CheckDuplicatesMethod'] == 1) { - if ($this->curItem->GetID()) { - $load_keys = Array($this->curItem->IDField => $this->curItem->GetID()); - } - } - else { - $key_fields = $this->exportOptions['DuplicateCheckFields']; - foreach ($key_fields as $key_field) { - $load_keys[$key_field] = $this->curItem->GetDBField($key_field); - } - } - - $this->resetImportObject($event, IMPORT_LIVE); - - if (count($load_keys)) { - $where_clause = ''; - foreach ($load_keys as $field_name => $field_value) { - if (preg_match('/^cust_(.*)/', $field_name, $regs)) { - $custom_id = array_search($regs[1], $this->customFields); - $field_name = 'l'.$this->Application->GetVar('m_lang').'_cust_'.$custom_id; - $where_clause .= '(custom_data.`'.$field_name.'` = '.$this->Conn->qstr($field_value).') AND '; - } - else { - $where_clause .= '(item_table.`'.$field_name.'` = '.$this->Conn->qstr($field_value).') AND '; - } - - } - $where_clause = preg_replace('/(.*) AND $/', '\\1', $where_clause); - - $item_id = $this->getFromCache('new_ids', crc32($where_clause)); - if (!$item_id) { - if ($this->exportOptions['CheckDuplicatesMethod'] == 2) { - // by other fields - $parent_path = $this->getParentPath($category_id); - $where_clause = '(c.ParentPath LIKE "'.$parent_path.'%") AND '.$where_clause; - } - - $cdata_table = $this->Application->getUnitOption($event->Prefix.'-cdata', 'TableName'); - $sql = 'SELECT '.$this->curItem->IDField.' - FROM '.$this->curItem->TableName.' item_table - LEFT JOIN '.$cdata_table.' custom_data ON custom_data.ResourceId = item_table.ResourceId - LEFT JOIN '.TABLE_PREFIX.'CategoryItems ci ON ci.ItemResourceId = item_table.ResourceId - LEFT JOIN '.TABLE_PREFIX.'Category c ON c.CategoryId = ci.CategoryId - WHERE '.$where_clause; - $item_id = $this->Conn->GetOne($sql); - } - $save_method = $item_id && $this->curItem->Load($item_id) ? 'Update' : 'Create'; - if ($save_method == 'Update') { - // replace id from csv file with found id - $record_data[ array_search($this->curItem->IDField, $this->exportFields) ] = $item_id; - } - } - - $this->setImportData($record_data); - } - else { - $this->resetImportObject($event, IMPORT_LIVE, $record_data); - $category_id = $this->getItemCategory(); - } - - // create main record - if ($save_method == 'Create') { - $this->fillRequiredFields($this->false, $this->curItem, true); - } - -// $sql_start = getmicrotime(); - if (!$this->curItem->$save_method()) { - $this->Application->SetVar('m_cat_id', $backup_category_id); - return false; - } -// $sql_end = getmicrotime(); -// $this->saveLog('SQL ['.$save_method.'] Time: '.($sql_end - $sql_start).'s'); - - if ($load_keys && ($save_method == 'Create') && $this->exportOptions['ReplaceDuplicates']) { - // map new id to old id - $this->addToCache('new_ids', crc32($where_clause), $this->curItem->GetID() ); - } - - // assign item to categories - $this->curItem->assignToCategory($category_id, false); - - $this->Application->SetVar('m_cat_id', $backup_category_id); - return true; - } - - /*function saveLog($msg) - { - static $first_time = true; - - $fp = fopen(FULL_PATH.'/sqls.log', $first_time ? 'w' : 'a'); - fwrite($fp, $msg."\n"); - fclose($fp); - - $first_time = false; - }*/ - - /** - * Returns category parent path, if possible, then from cache - * - * @param int $category_id - * @return string - */ - function getParentPath($category_id) - { - $parent_path = $this->getFromCache('category_parent_path', $category_id); - if ($parent_path === false) { - $sql = 'SELECT ParentPath - FROM '.TABLE_PREFIX.'Category - WHERE CategoryId = '.$category_id; - $parent_path = $this->Conn->GetOne($sql); - $this->addToCache('category_parent_path', $category_id, $parent_path); - } - return $parent_path; - } - - function getFileExtension() - { - return $this->exportOptions['ExportFormat'] == 1 ? 'csv' : 'xml'; - } - - function getLineSeparator($option = 'LineEndings') - { - return $this->exportOptions[$option] == 1 ? "\r\n" : "\n"; - } - - /** - * Returns field caption for any exported field - * - * @param string $field - * @return string - */ - function getFieldCaption($field) - { - if (substr($field, 0, 10) == '__CUSTOM__') - { - $ret = 'Custom_'.substr($field, 10, strlen($field) ); - } - elseif (substr($field, 0, 12) == '__CATEGORY__') - { - return $this->getCategoryTitle(); - } - elseif (substr($field, 0, 11) == '__VIRTUAL__') { - $ret = substr($field, 11); - } - else - { - $ret = $field; - } - - return Array($ret); - } - - /** - * Returns requested field value (including custom fields and category fields) - * - * @param string $field - * @return string - */ - function getFieldValue($field) - { - if (substr($field, 0, 10) == '__CUSTOM__') { - $field = 'cust_'.substr($field, 10, strlen($field)); - $ret = $this->curItem->GetField($field); - } - elseif (substr($field, 0, 12) == '__CATEGORY__') { - return $this->getCategoryPath(); - } - elseif (substr($field, 0, 11) == '__VIRTUAL__') { - $field = substr($field, 11); - $ret = $this->curItem->GetField($field); - } - else - { - $ret = $this->curItem->GetField($field); - } - - $ret = str_replace("\r\n", $this->getLineSeparator('LineEndingsInside'), $ret); - return Array($ret); - } - - /** - * Returns category field(-s) caption based on export mode - * - * @return string - */ - function getCategoryTitle() - { - // category path in separated fields - $category_count = $this->getMaxCategoryLevel(); - if ($this->exportOptions['CategoryFormat'] == 1) - { - // category path in one field - return $category_count ? Array('CategoryPath') : Array(); - } - else - { - $i = 0; - $ret = Array(); - while ($i < $category_count) { - $ret[] = 'Category'.($i + 1); - $i++; - } - return $ret; - } - } - - /** - * Returns category path in required format for current link - * - * @return string - */ - function getCategoryPath() - { - $category_id = $this->curItem->GetDBField('CategoryId'); - $category_path = $this->getFromCache('category_path', $category_id); - if (!$category_path) - { - $ml_formatter =& $this->Application->recallObject('kMultiLanguage'); - $sql = 'SELECT '.$ml_formatter->LangFieldName('CachedNavbar').' - FROM '.TABLE_PREFIX.'Category - WHERE CategoryId = '.$category_id; - $category_path = $this->Conn->GetOne($sql); - $category_path = $category_path ? explode('&|&', $category_path) : Array(); - - if ($this->exportOptions['IsBaseCategory']) { - $i = $this->exportOptions['BaseLevel']; - while ($i > 0) { - array_shift($category_path); - $i--; - } - } - - $category_count = $this->getMaxCategoryLevel(); - if ($this->exportOptions['CategoryFormat'] == 1) { - // category path in single field - $category_path = $category_count ? Array( implode($this->exportOptions['CategorySeparator'], $category_path) ) : Array(); - } - else { - // category path in separated fields - $levels_used = count($category_path); - if ($levels_used < $category_count) - { - $i = 0; - while ($i < $category_count - $levels_used) { - $category_path[] = ''; - $i++; - } - } - } - $this->addToCache('category_path', $category_id, $category_path); - } - - return $category_path; - } - - /** - * Get maximal category deep level from links beeing exported - * - * @return int - */ - function getMaxCategoryLevel() - { - static $max_level = -1; - - if ($max_level != -1) - { - return $max_level; - } - - $sql = 'SELECT IF(c.CategoryId IS NULL, 0, MAX( LENGTH(c.ParentPath) - LENGTH( REPLACE(c.ParentPath, "|", "") ) - 1 )) - FROM '.$this->curItem->TableName.' item_table - LEFT JOIN '.TABLE_PREFIX.'CategoryItems ci ON item_table.ResourceId = ci.ItemResourceId - LEFT JOIN '.TABLE_PREFIX.'Category c ON c.CategoryId = ci.CategoryId - WHERE (ci.PrimaryCat = 1) AND '; - - $where_clause = ''; - if ($this->exportOptions['export_ids'] === false) { - // get links from current category & all it's subcategories - if ($this->exportOptions['export_cats_ids'][0] == 0) { - $where_clause = 1; - } - else { - foreach ($this->exportOptions['export_cats_ids'] as $category_id) { - $where_clause .= '(c.ParentPath LIKE "%|'.$category_id.'|%") OR '; - } - $where_clause = preg_replace('/(.*) OR $/', '\\1', $where_clause); - } - } - else { - // get only selected links - $where_clause = $this->curItem->IDField.' IN ('.implode(',', $this->exportOptions['export_ids']).')'; - } - - $max_level = $this->Conn->GetOne($sql.'('.$where_clause.')'); - - if ($this->exportOptions['IsBaseCategory'] ) { - $max_level -= $this->exportOptions['BaseLevel']; - } - - return $max_level; - } - - /** - * Saves one record to export file - * - * @param Array $fields_hash - */ - function writeRecord($fields_hash) - { - fputcsv2($this->filePointer, $fields_hash, $this->exportOptions['FieldsSeparatedBy'], $this->exportOptions['FieldsEnclosedBy'], $this->getLineSeparator() ); - } - - function readRecord() - { - return fgetcsv($this->filePointer, 10000, $this->exportOptions['FieldsSeparatedBy'], $this->exportOptions['FieldsEnclosedBy']); - } - - function saveOptions(&$event, $options = null) - { - if (!isset($options)) { - $options = $this->exportOptions; - } - $this->Application->StoreVar($event->getPrefixSpecial().'_options', serialize($options) ); - } - - function loadOptions(&$event) - { - return unserialize($this->Application->RecallVar($event->getPrefixSpecial().'_options')); - } - - /** - * Sets correct available & export fields - * - * @param kEvent $event - */ - function prepareExportColumns(&$event) - { - $object =& $event->getObject( Array('skip_autoload' => true) ); - - $available_columns = Array(); - - if ($this->Application->getUnitOption($event->Prefix, 'CatalogItem')) { - // category field (mixed) - $available_columns['__CATEGORY__CategoryPath'] = 'CategoryPath'; - - if ($event->Special == 'import') { - // category field (separated fields) - $max_level = $this->Application->ConfigValue('MaxImportCategoryLevels'); - $i = 0; - while ($i < $max_level) { - $available_columns['__CATEGORY__Category'.($i + 1)] = 'Category'.($i + 1); - $i++; - } - } - } - - // db fields - foreach ($object->Fields as $field_name => $field_options) - { - if (!$object->SkipField($field_name)) - { - $available_columns[$field_name] = $field_name.(getArrayValue($field_options, 'required') ? '*' : ''); - } - } - - $handler =& $this->Application->recallObject($event->Prefix.'_EventHandler'); - $available_columns = array_merge_recursive2($available_columns, $handler->getCustomExportColumns($event)); - - // custom fields - foreach ($object->customFields as $custom_id => $custom_name) - { - $available_columns['__CUSTOM__'.$custom_name] = $custom_name; - } - - // columns already in use - $items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) ); - if ($items_info) - { - list($item_id, $field_values) = each($items_info); - $export_keys = $field_values['ExportColumns']; - $export_keys = $export_keys ? explode('|', substr($export_keys, 1, -1) ) : Array(); - } - else { - $export_keys = Array(); - } - - $export_columns = Array(); - foreach ($export_keys as $field_key) - { - $field_name = $this->getExportField($field_key); - $export_columns[$field_key] = $field_name; - unset($available_columns[$field_key]); - } - - $options = $object->GetFieldOptions('ExportColumns'); - $options['options'] = $export_columns; - $object->SetFieldOptions('ExportColumns', $options); - - $options = $object->GetFieldOptions('AvailableColumns'); - $options['options'] = $available_columns; - $object->SetFieldOptions('AvailableColumns', $options); - - $this->updateImportFiles($event); - $this->PrepareExportPresets($event); - } - - function PrepareExportPresets(&$event) - { - $object =& $event->getObject( Array('skip_autoload' => true) ); - $options = $object->GetFieldOptions('ExportPresets'); - - $user =& $this->Application->recallObject('u.current'); - $export_settings = $user->getPersistantVar('export_settings'); - if (!$export_settings) return ; - $export_settings = unserialize($export_settings); - - if (!isset($export_settings[$event->Prefix])) return ; - - - $export_presets = array(''=>''); - foreach ($export_settings[$event->Prefix] as $key => $val) { - $export_presets[implode('|', $val['ExportColumns'])] = $key; - } - - $options['options'] = $export_presets; - $object->SetFieldOptions('ExportPresets', $options); - } - - function getExportField($field_key) - { - $prepends = Array('__CUSTOM__', '__CATEGORY__'); - foreach ($prepends as $prepend) - { - if (substr($field_key, 0, strlen($prepend) ) == $prepend) - { - $field_key = substr($field_key, strlen($prepend), strlen($field_key) ); - break; - } - } - return $field_key; - } - - /** - * Updates uploaded files list - * - * @param kEvent $event - */ - function updateImportFiles(&$event) - { - if ($event->Special != 'import') { - return false; - } - - $object =& $event->getObject(); - - $import_filenames = Array(); - - if ($folder_handle = opendir(EXPORT_PATH)) { - while (false !== ($file = readdir($folder_handle))) { - if (is_dir(EXPORT_PATH.'/'.$file) || substr($file, 0, 1) == '.' || strtolower($file) == 'cvs' || strtolower($file) == 'dummy' || filesize(EXPORT_PATH.'/'.$file) == 0) continue; - - $file_size = formatSize( filesize(EXPORT_PATH.'/'.$file) ); - $import_filenames[$file] = $file.' ('.$file_size.')'; - } - closedir($folder_handle); - } - - $options = $object->GetFieldOptions('ImportLocalFilename'); - $options['options'] = $import_filenames; - $object->SetFieldOptions('ImportLocalFilename', $options); - } - - /** - * Returns module folder - * - * @param kEvent $event - * @return string - */ - function getModuleFolder(&$event) - { - return $this->Application->getUnitOption($event->Prefix, 'ModuleFolder'); - } - - /** - * Export form validation & processing - * - * @param kEvent $event - */ - function OnExportBegin(&$event) - { - $items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) ); - if (!$items_info) - { - $items_info = unserialize( $this->Application->RecallVar($event->getPrefixSpecial().'_ItemsInfo') ); - $this->Application->SetVar($event->getPrefixSpecial(true), $items_info); - } - - list($item_id, $field_values) = each($items_info); - - $object =& $event->getObject( Array('skip_autoload' => true) ); - $object->SetFieldsFromHash($field_values); - $field_values['ImportFilename'] = $object->GetDBField('ImportFilename'); //if upload formatter has renamed the file during moving !!! - - $object->setID($item_id); - $this->setRequiredFields($event); - - $export_object =& $this->Application->recallObject('CatItemExportHelper'); - - // save export/import options - if ($event->Special == 'export') - { - $export_ids = $this->Application->RecallVar($event->Prefix.'_export_ids'); - $export_cats_ids = $this->Application->RecallVar($event->Prefix.'_export_cats_ids'); - - // used for multistep export - $field_values['export_ids'] = $export_ids ? explode(',', $export_ids) : false; - $field_values['export_cats_ids'] = $export_cats_ids ? explode(',', $export_cats_ids) : Array( $this->Application->GetVar('m_cat_id') ); - } - - $field_values['ExportColumns'] = $field_values['ExportColumns'] ? explode('|', substr($field_values['ExportColumns'], 1, -1) ) : Array(); - $field_values['start_from'] = 0; - - $this->Application->HandleEvent($nevent, $event->Prefix.':OnBeforeExportBegin', array('options'=>$field_values)); - $field_values = $nevent->getEventParam('options'); - - $export_object->saveOptions($event, $field_values); - - if( $export_object->verifyOptions($event) ) - { - if ($object->GetDBField('ExportSavePreset')) { - $name = $object->GetDBField('ExportPresetName'); - $user =& $this->Application->recallObject('u.current'); - $export_settings = $user->getPersistantVar('export_settings'); - $export_settings = $export_settings ? unserialize($export_settings) : array(); - $export_settings[$event->Prefix][$name] = $field_values; - $user->setPersistantVar('export_settings', serialize($export_settings)); - } - - $progress_t = $this->Application->RecallVar('export_progress_t'); - if ($progress_t) { - $this->Application->RemoveVar('export_progress_t'); - } - else { - $progress_t = $export_object->getModuleFolder($event).'/'.$event->Special.'_progress'; - } - $event->redirect = $progress_t; - } - else - { - // make uploaded file local & change source selection - $filename = getArrayValue($field_values, 'ImportFilename'); - if ($filename) { - $export_object->updateImportFiles($event); - $object->SetDBField('ImportSource', 2); - $field_values['ImportSource'] = 2; - $object->SetDBField('ImportLocalFilename', $filename); - $field_values['ImportLocalFilename'] = $filename; - $export_object->saveOptions($event, $field_values); - } - - $event->status = erFAIL; - $event->redirect = false; - } - } - - /** - * set required fields based on import or export params - * - * @param kEvent $event - */ - function setRequiredFields(&$event) - { - $required_fields['common'] = Array('FieldsSeparatedBy', 'LineEndings', 'CategoryFormat'); - - $required_fields['export'] = Array('ExportFormat', 'ExportFilename','ExportColumns'); - - $object =& $event->getObject(); - if ($object->GetDBField('ExportSavePreset')) { - $required_fields['export'][] = 'ExportPresetName'; - } - - $required_fields['import'] = Array('FieldTitles', 'ImportSource', 'CheckDuplicatesMethod'); // ImportFilename, ImportLocalFilename - - if ($event->Special == 'import') - { - $import_source = Array(1 => 'ImportFilename', 2 => 'ImportLocalFilename'); - $used_field = $import_source[ $object->GetDBField('ImportSource') ]; - - $required_fields[$event->Special][] = $used_field; - $object->Fields[$used_field]['error_field'] = 'ImportSource'; - - if ($object->GetDBField('FieldTitles') == 2) $required_fields[$event->Special][] = 'ExportColumns'; // manual field titles - } - - $required_fields = array_merge($required_fields['common'], $required_fields[$event->Special]); - foreach ($required_fields as $required_field) { - $object->setRequired($required_field, true); - } - } - - } - -?>