Page Menu
Home
In-Portal Phabricator
Search
Configure Global Search
Log In
Files
F1068969
in-portal
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Sat, Jul 19, 4:43 AM
Size
64 KB
Mime Type
text/x-diff
Expires
Mon, Jul 21, 4:43 AM (20 h, 23 m)
Engine
blob
Format
Raw Data
Handle
691959
Attached To
rINP In-Portal
in-portal
View Options
Index: branches/unlabeled/unlabeled-1.14.2/kernel/units/general/cat_dbitem_export.php
===================================================================
--- branches/unlabeled/unlabeled-1.14.2/kernel/units/general/cat_dbitem_export.php (revision 4163)
+++ branches/unlabeled/unlabeled-1.14.2/kernel/units/general/cat_dbitem_export.php (revision 4164)
@@ -1,1062 +1,1062 @@
<?php
define('EXPORT_STEP', 200); // export by 200 items (e.g. links)
define('IMPORT_CHUNK', 30720); // 10240); //30720); //50120); // 5 KB
define('IMPORT_TEMP', 1);
define('IMPORT_LIVE', 2);
class kCatDBItemExportHelper extends kHelper {
var $false = false;
var $cache = Array();
/**
* Allows to find out what items are new in cache
*
* @var Array
*/
var $cacheStatus = Array();
var $cacheTable = '';
var $exportFields = Array();
/**
* Export options
*
* @var Array
*/
var $exportOptions = Array();
/**
* If we have custom fields in export
*
* @var unknown_type
*/
var $hasCustomFields = false;
/**
* Custom field values for last item beeing exported
*
* @var Array
*/
var $customValues = Array();
/**
* Item beeing currenly exported
*
* @var kCatDBItem
*/
var $curItem = null;
/**
* Dummy category object
*
* @var CategoriesItem
*/
var $dummyCategory = null;
/**
* Pointer to opened file
*
* @var resource
*/
var $filePointer = null;
function kCatDBItemExportHelper()
{
parent::kHelper();
$this->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->SetDBField($field_name, isset($sample_value) && $sample_value ? $sample_value : 'no value');
}
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->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) {
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 getExportSQL($count_only = false)
{
if ($this->exportOptions['export_ids'] === false)
{
// get links from current category & all it's subcategories
$sql = 'SELECT item_table.*, ci.CategoryId
FROM '.$this->curItem->TableName.' item_table
LEFT JOIN '.TABLE_PREFIX.'CategoryItems ci ON ci.ItemResourceId = item_table.ResourceId
LEFT JOIN '.TABLE_PREFIX.'Category c ON c.CategoryId = ci.CategoryId
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->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 CachedNavbar
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) );
$this->exportOptions['has_custom_fields'] = $this->scanCustomFields();
}
$this->hasCustomFields = $this->exportOptions['has_custom_fields'];
// 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() );
if ($this->hasCustomFields)
{
$this->loadItemCustomFields();
}
$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']);
while (($bytes_imported < IMPORT_CHUNK) && !feof($this->filePointer)) {
$this->customValues = Array();
$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'];
}
$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 = substr($field_name, 7);
$this->customValues[$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) ] = $value;
+ $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();
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()
{
$backup_category_id = $this->Application->GetVar('m_cat_id');
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 (Name = '.$this->Conn->qstr($category_name).') AND (ParentPath LIKE "'.$parent_path.'%")';
+ WHERE (Name = '.$this->Conn->qstr($category_name).') AND (ParentPath LIKE "'.$parent_path.'%") AND (ParentPath <> "'.$parent_path.'")';
$category_id = $this->Conn->GetOne($sql);
if ($category_id === false) {
// category not in db -> create
$category_fields = Array( 'Name' => $category_name, '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) {
$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;
}
$sql = 'SELECT '.$this->curItem->IDField.'
FROM '.$this->curItem->TableName.' item_table
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';
}
$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()) {
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() );
}
// set custom fields
foreach ($this->customValues as $custom_field => $custom_value) {
if (($save_method == 'Create') && !$custom_value) continue;
$this->curItem->SetCustomField($custom_field, $custom_value);
}
// assign item to categories
$this->curItem->assignToCategory($category_id, false);
$this->Application->SetVar('m_cat_id', $backup_category_id);
return true;
}
/*function saveLog($msg)
{
$fp = fopen(FULL_PATH.'/sqls.log', 'a');
fwrite($fp, $msg."\n");
fclose($fp);
}*/
/**
* 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 loadItemCustomFields()
{
$sql = 'SELECT meta_data.Value, cf.FieldName
FROM '.TABLE_PREFIX.'CustomMetaData meta_data
LEFT JOIN '.TABLE_PREFIX.'CustomField cf ON cf.CustomFieldId = meta_data.CustomFieldId
WHERE meta_data.ResourceId = '.$this->curItem->GetDBField('ResourceId');
$this->customValues = $this->Conn->GetCol($sql, 'FieldName');
}
function getFileExtension()
{
return $this->exportOptions['ExportFormat'] == 1 ? 'csv' : 'xml';
}
function getLineSeparator($option = 'LineEndings')
{
return $this->exportOptions[$option] == 1 ? "\r\n" : "\n";
}
function scanCustomFields()
{
$ret = false;
$export_fields = $this->exportOptions['ExportColumns'];
foreach ($export_fields as $field)
{
if (substr($field, 0, 10) == '__CUSTOM__')
{
$ret = true;
break;
}
}
return $ret;
}
/**
* 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 = substr($field, 10, strlen($field) );
$ret = isset($this->customValues[$field]) ? $this->customValues[$field] : '';
}
elseif (substr($field, 0, 12) == '__CATEGORY__') {
return $this->getCategoryPath();
}
elseif (substr($field, 0, 11) == '__VIRTUAL__') {
$field = substr($field, 11);
return $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)
{
$sql = 'SELECT 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'));
}
}
?>
Property changes on: branches/unlabeled/unlabeled-1.14.2/kernel/units/general/cat_dbitem_export.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.14.2.3
\ No newline at end of property
+1.14.2.4
\ No newline at end of property
Index: branches/unlabeled/unlabeled-1.14.2/core/units/general/cat_dbitem_export.php
===================================================================
--- branches/unlabeled/unlabeled-1.14.2/core/units/general/cat_dbitem_export.php (revision 4163)
+++ branches/unlabeled/unlabeled-1.14.2/core/units/general/cat_dbitem_export.php (revision 4164)
@@ -1,1062 +1,1062 @@
<?php
define('EXPORT_STEP', 200); // export by 200 items (e.g. links)
define('IMPORT_CHUNK', 30720); // 10240); //30720); //50120); // 5 KB
define('IMPORT_TEMP', 1);
define('IMPORT_LIVE', 2);
class kCatDBItemExportHelper extends kHelper {
var $false = false;
var $cache = Array();
/**
* Allows to find out what items are new in cache
*
* @var Array
*/
var $cacheStatus = Array();
var $cacheTable = '';
var $exportFields = Array();
/**
* Export options
*
* @var Array
*/
var $exportOptions = Array();
/**
* If we have custom fields in export
*
* @var unknown_type
*/
var $hasCustomFields = false;
/**
* Custom field values for last item beeing exported
*
* @var Array
*/
var $customValues = Array();
/**
* Item beeing currenly exported
*
* @var kCatDBItem
*/
var $curItem = null;
/**
* Dummy category object
*
* @var CategoriesItem
*/
var $dummyCategory = null;
/**
* Pointer to opened file
*
* @var resource
*/
var $filePointer = null;
function kCatDBItemExportHelper()
{
parent::kHelper();
$this->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->SetDBField($field_name, isset($sample_value) && $sample_value ? $sample_value : 'no value');
}
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->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) {
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 getExportSQL($count_only = false)
{
if ($this->exportOptions['export_ids'] === false)
{
// get links from current category & all it's subcategories
$sql = 'SELECT item_table.*, ci.CategoryId
FROM '.$this->curItem->TableName.' item_table
LEFT JOIN '.TABLE_PREFIX.'CategoryItems ci ON ci.ItemResourceId = item_table.ResourceId
LEFT JOIN '.TABLE_PREFIX.'Category c ON c.CategoryId = ci.CategoryId
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->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 CachedNavbar
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) );
$this->exportOptions['has_custom_fields'] = $this->scanCustomFields();
}
$this->hasCustomFields = $this->exportOptions['has_custom_fields'];
// 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() );
if ($this->hasCustomFields)
{
$this->loadItemCustomFields();
}
$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']);
while (($bytes_imported < IMPORT_CHUNK) && !feof($this->filePointer)) {
$this->customValues = Array();
$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'];
}
$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 = substr($field_name, 7);
$this->customValues[$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) ] = $value;
+ $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();
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()
{
$backup_category_id = $this->Application->GetVar('m_cat_id');
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 (Name = '.$this->Conn->qstr($category_name).') AND (ParentPath LIKE "'.$parent_path.'%")';
+ WHERE (Name = '.$this->Conn->qstr($category_name).') AND (ParentPath LIKE "'.$parent_path.'%") AND (ParentPath <> "'.$parent_path.'")';
$category_id = $this->Conn->GetOne($sql);
if ($category_id === false) {
// category not in db -> create
$category_fields = Array( 'Name' => $category_name, '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) {
$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;
}
$sql = 'SELECT '.$this->curItem->IDField.'
FROM '.$this->curItem->TableName.' item_table
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';
}
$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()) {
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() );
}
// set custom fields
foreach ($this->customValues as $custom_field => $custom_value) {
if (($save_method == 'Create') && !$custom_value) continue;
$this->curItem->SetCustomField($custom_field, $custom_value);
}
// assign item to categories
$this->curItem->assignToCategory($category_id, false);
$this->Application->SetVar('m_cat_id', $backup_category_id);
return true;
}
/*function saveLog($msg)
{
$fp = fopen(FULL_PATH.'/sqls.log', 'a');
fwrite($fp, $msg."\n");
fclose($fp);
}*/
/**
* 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 loadItemCustomFields()
{
$sql = 'SELECT meta_data.Value, cf.FieldName
FROM '.TABLE_PREFIX.'CustomMetaData meta_data
LEFT JOIN '.TABLE_PREFIX.'CustomField cf ON cf.CustomFieldId = meta_data.CustomFieldId
WHERE meta_data.ResourceId = '.$this->curItem->GetDBField('ResourceId');
$this->customValues = $this->Conn->GetCol($sql, 'FieldName');
}
function getFileExtension()
{
return $this->exportOptions['ExportFormat'] == 1 ? 'csv' : 'xml';
}
function getLineSeparator($option = 'LineEndings')
{
return $this->exportOptions[$option] == 1 ? "\r\n" : "\n";
}
function scanCustomFields()
{
$ret = false;
$export_fields = $this->exportOptions['ExportColumns'];
foreach ($export_fields as $field)
{
if (substr($field, 0, 10) == '__CUSTOM__')
{
$ret = true;
break;
}
}
return $ret;
}
/**
* 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 = substr($field, 10, strlen($field) );
$ret = isset($this->customValues[$field]) ? $this->customValues[$field] : '';
}
elseif (substr($field, 0, 12) == '__CATEGORY__') {
return $this->getCategoryPath();
}
elseif (substr($field, 0, 11) == '__VIRTUAL__') {
$field = substr($field, 11);
return $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)
{
$sql = 'SELECT 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'));
}
}
?>
Property changes on: branches/unlabeled/unlabeled-1.14.2/core/units/general/cat_dbitem_export.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.14.2.3
\ No newline at end of property
+1.14.2.4
\ No newline at end of property
Event Timeline
Log In to Comment