You are here

uc_importer.module in Ubercart 5

XML product importer and exporter.

Imports and exports product nodes, as well as the taxonomy vocabularies, categories, manufacturers, classes, and attributes that are associated with them.

Coded by Lyle Mantooth.

File

uc_importer/uc_importer.module
View source
<?php

/**
 * @file
 *
 * XML product importer and exporter.
 *
 * Imports and exports product nodes, as well as the taxonomy vocabularies,
 * categories, manufacturers, classes, and attributes that are associated with them.
 *
 * Coded by Lyle Mantooth.
 */

/**
 * Do not save objects if the database already contains their names.
 */
define('UC_IMPORTER_DO_NOTHING', 0);

/**
 * Replace objects if the database already contains their names.
 */
define('UC_IMPORTER_REPLACE', 1);

/**
 * Append '_#' to the names of objects already in the database.
 */
define('UC_IMPORTER_INCREMENT', 2);

/******************************************************************************
 * Drupal Hooks                                                               *
 ******************************************************************************/

/**
 * Implementation of hook_perm().
 */
function uc_importer_perm() {
  return array(
    'import',
    'export',
  );
}

/**
 * Implementation of hook_menu().
 */
function uc_importer_menu($may_cache) {
  $items = array();
  if ($may_cache) {
    $items[] = array(
      'path' => 'admin/store/products/export',
      'access' => user_access('export'),
      'title' => t('Export products'),
      'callback' => 'uc_importer_export_page',
      'type' => MENU_NORMAL_ITEM,
    );
    $items[] = array(
      'path' => 'admin/store/products/import',
      'access' => user_access('import'),
      'title' => t('Import products'),
      'callback' => 'uc_importer_import_page',
      'type' => MENU_NORMAL_ITEM,
    );
    $items[] = array(
      'path' => 'admin/store/settings/importer',
      'access' => user_access('import'),
      'title' => t('Importer settings'),
      'description' => t('Configure the importer settings.'),
      'callback' => 'drupal_get_form',
      'callback arguments' => array(
        'uc_importer_admin_settings',
      ),
      'type' => MENU_NORMAL_ITEM,
    );
  }
  return $items;
}

/******************************************************************************
 * Menu Callbacks                                                             *
 ******************************************************************************/

/**
 * Configure the importer behaviour when handling duplicate objects.
 *
 * @ingroup forms
 * @see uc_importer_admin_settings_validate
 * @see uc_importer_admin_settings_submit
 */
function uc_importer_admin_settings() {
  $form = array();
  $options = array(
    UC_IMPORTER_DO_NOTHING => t('Do not save the new item.'),
    UC_IMPORTER_REPLACE => t('Overwrite the existing item.'),
    UC_IMPORTER_INCREMENT => t('Save the new item as a separate entity,'),
  );
  $form['uc_importer_vocabulary_duplicates'] = array(
    '#type' => 'radios',
    '#title' => t('How should similarly named vocabularies be handled during import?'),
    '#options' => $options,
    '#default_value' => variable_get('uc_importer_vocabulary_duplicates', UC_IMPORTER_DO_NOTHING),
  );
  $form['uc_importer_category_duplicates'] = array(
    '#type' => 'radios',
    '#title' => t('How should similarly named categories be handled during import?'),
    '#options' => $options,
    '#default_value' => variable_get('uc_importer_category_duplicates', UC_IMPORTER_DO_NOTHING),
  );
  $form['uc_importer_class_duplicates'] = array(
    '#type' => 'radios',
    '#title' => t('How should similarly named classes be handled during import?'),
    '#options' => $options,
    '#default_value' => variable_get('uc_importer_class_duplicates', UC_IMPORTER_DO_NOTHING),
  );
  $form['uc_importer_attribute_duplicates'] = array(
    '#type' => 'radios',
    '#title' => t('How should similarly named attributes be handled during import?'),
    '#options' => $options,
    '#default_value' => variable_get('uc_importer_attribute_duplicates', UC_IMPORTER_DO_NOTHING),
  );
  $form['uc_importer_product_duplicates'] = array(
    '#type' => 'radios',
    '#title' => t('How should similarly identified products be handled during import?'),
    '#options' => $options,
    '#default_value' => variable_get('uc_importer_product_duplicates', UC_IMPORTER_DO_NOTHING),
  );
  $account = user_load(array(
    'uid' => variable_get('uc_importer_user', 0),
  ));
  $form['uc_importer_user'] = array(
    '#type' => 'textfield',
    '#title' => t('Authored by'),
    '#maxlength' => 60,
    '#autocomplete_path' => 'user/autocomplete',
    '#default_value' => $account ? $account->name : '',
    '#description' => t('The "author" of imported products. Leave blank for %anonymous.', array(
      '%anonymous' => variable_get('anonymous', t('Anonymous')),
    )),
  );
  $form['buttons']['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Save configuration'),
  );
  $form['buttons']['reset'] = array(
    '#type' => 'submit',
    '#value' => t('Reset to defaults'),
  );
  if (!empty($_POST) && form_get_errors()) {
    drupal_set_message(t('The settings have not been saved because of the errors.'), 'error');
  }
  return $form;
}

/**
 * Validation handler for uc_importer_admin_settings().
 *
 * Allow only existing users to be authors of imported nodes.
 */
function uc_importer_admin_settings_validate($form_id, $form_values) {
  if (!empty($form_values['uc_importer_user']) && !($account = user_load(array(
    'name' => $form_values['uc_importer_user'],
  )))) {

    // The use of empty() is mandatory in the context of usernames
    // as the empty string denotes the anonymous user. In case we
    // are dealing with an anonymous user we set the user ID to 0.
    form_set_error('uc_importer_user', t('The username %name does not exist.', array(
      '%name' => $form_values['uc_importer_user'],
    )));
  }
}

/**
 * Submit handler for uc_importer_admin_settings().
 */
function uc_importer_admin_settings_submit($form_id, $form_values) {
  if ($op == t('Reset to defaults')) {
    variable_del('uc_importer_handle_duplicates');
    variable_del('uc_importer_user');
    drupal_set_message(t('The configuration options have been reset to their default values.'));
  }
  else {
    if ($account = user_load(array(
      'name' => $form_values['uc_importer_user'],
    ))) {
      variable_set('uc_importer_user', $account->uid);
    }
    else {
      variable_set('uc_importer_user', 0);
    }
    variable_set('uc_importer_vocabulary_duplicates', $form_values['uc_importer_vocabulary_duplicates']);
    variable_set('uc_importer_category_duplicates', $form_values['uc_importer_category_duplicates']);
    variable_set('uc_importer_class_duplicates', $form_values['uc_importer_class_duplicates']);
    variable_set('uc_importer_attribute_duplicates', $form_values['uc_importer_attribute_duplicates']);
    variable_set('uc_importer_product_duplicates', $form_values['uc_importer_product_duplicates']);
    drupal_set_message(t('The configuration options have been saved.'));
  }
}

/**
 * Wrapper function to generate a page to hold the export form.
 */
function uc_importer_export_page() {
  uc_add_js(drupal_get_path('module', 'uc_product') . '/uc_product.js', 'module');
  $output = '';
  $nids = array();
  $args = func_get_args();
  foreach ($args as $nid) {
    if (is_numeric($nid)) {
      $nids[] = (int) $nid;
    }
  }
  $settings = array(
    'div' => '#products-selector',
    'class' => 'product-ubrowser',
    'vid' => variable_get('uc_catalog_vid', 0),
    'filter' => implode(',', module_invoke_all('product_types')),
    'search' => 'true',
    'nids' => 'true',
    'nodesg' => 'product',
    'nodepl' => 'products',
    'multi' => 'true',
    'select' => 'buffer_products("' . file_create_url('') . '")',
  );
  if (module_exists('uc_catalog') && variable_get('uc_catalog_vid', 0)) {
    $output .= ubrowser($settings, 'products-selector');
    $output .= drupal_get_form('uc_importer_export_buffer_form', $nids);
  }
  else {
    $output .= drupal_get_form('uc_importer_export_form');
  }
  return $output;
}

/**
 * Wrapper function to generate a page to hold the import form.
 */
function uc_importer_import_page() {
  return drupal_get_form('uc_importer_import_form');
}

/******************************************************************************
 * Module Functions                                                           *
 ******************************************************************************/

/**
 * Choose the nodes to export.
 *
 * @ingroup forms
 * @see uc_importer_export_form_submit
 */
function uc_importer_export_form() {
  $form = array();
  $products = array();
  $result = db_query(db_rewrite_sql("SELECT n.nid, p.model FROM {uc_products} AS p JOIN {node} AS n"));
  while ($product = db_fetch_object($result)) {
    $products[$product->nid] = $product->model;
  }
  $form['nids'] = array(
    '#type' => 'select',
    '#multiple' => true,
    '#title' => t('Products'),
    '#options' => $products,
    '#description' => t('Hold "Ctrl" to select multiple items.'),
  );
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Export'),
  );
  return $form;
}

/**
 * Submit handler for uc_importer_form().
 */
function uc_importer_export_form_submit($form_id, $form_values) {
  if (count($form_values['nids'])) {
    $xml = uc_importer_export((array) $form_values['nids']);
    if ($file = file_save_data($xml, file_directory_temp() . '/uc_export.xml', FILE_EXISTS_REPLACE)) {

      //drupal_set_message(print_r($file, true));
      file_transfer($file, array(
        'Content-Type: application/xml; charset=utf-8',
        'Content-Length: ' . filesize($file),
        'Content-Disposition: attachment; filename="uc_export.xml"',
      ));
    }
  }
}

/**
 * Form to collect the id numbers of all the store components to be exported.
 *
 * @ingroup forms
 * @see uc_importer_export_buffer_form_submit
 */
function uc_importer_export_buffer_form($nids) {
  $form = array();
  $buffer = '';
  foreach ($nids as $nid) {
    $node = node_load($nid);
    $buffer .= theme('imagecache', 'uc_thumbnail', $node->field_image_cache[0]['filepath'], $node->field_image_cache[0]['alt'], $node->field_image_cache[0]['title']);
  }
  $form['#attributes'] = array(
    'class' => 'product-buffer',
  );
  $form['thumbnails'] = array(
    '#type' => 'markup',
    '#value' => '<div id="buffer-images"></div>',
  );
  $form['products'] = array(
    '#type' => 'hidden',
  );
  $form['reset'] = array(
    '#type' => 'submit',
    '#value' => t('Reset'),
  );
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Export'),
  );
  return $form;
}

/**
 * Submit handler for uc_importer_export_buffer_form().
 *
 * Generate an XML file from the products listed and upload it to the user.
 */
function uc_importer_export_buffer_form_submit($form_id, $form_values) {
  $item = menu_get_item(menu_get_active_item());

  //drupal_set_message(print_r($form_values, true));
  if ($form_values['op'] == t('Reset')) {
    return $item['path'];
  }
  else {
    $products = array_filter(explode('/', $form_values['products']));

    //drupal_set_message('<pre>'. print_r($products, true) .'</pre>');
    $xml = uc_importer_export($products);
    if ($file = file_save_data($xml, file_directory_temp() . '/uc_export.xml', FILE_EXISTS_REPLACE)) {

      //drupal_set_message(print_r($file, true));
      file_transfer($file, array(
        'Content-Type: application/xml',
        'Content-Length: ' . filesize($file),
        'Content-Disposition: attachment; filename="' . $file . '"',
      ));
    }
  }
}

/**
 * Upload form for an XML file to be imported.
 *
 * @ingroup forms
 * @see uc_importer_import_form_submit
 */
function uc_importer_import_form() {
  $form = array();
  $form['#attributes'] = array(
    'enctype' => "multipart/form-data",
  );
  $form['file'] = array(
    '#type' => 'file',
    '#title' => t('Import XML File'),
  );
  $form['directory'] = array(
    '#type' => 'textfield',
    '#title' => t('Directory containing XML files'),
  );
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Import'),
  );
  return $form;
}

/**
 * Submit function for uc_importer_import_form().
 */
function uc_importer_import_form_submit($form_id, $form_values) {
  $file = file_check_upload('file');
  if ($file) {
    $file = file_save_upload($file);
    drupal_set_message(t('File uploaded successfully.'));

    //drupal_set_message('<pre>'. print_r($file, true) .'</pre>');
    if ($xml = file_get_contents($file->filepath)) {
      uc_importer_import($xml);
    }
  }
  else {
    if ($form_values['directory']) {
      file_scan_directory(file_directory_path() . '/' . $form_values['directory'], '.*\\.xml$', array(
        '.',
        '..',
        'CVS',
      ), 'uc_import_directory_parse');
    }
    else {
      drupal_set_message(t('Error: File failed to upload.'), 'error');
    }
  }
}

/**
 * Constructs the XML representation of the store from the ids given.
 *
 * @param $nids
 *   An array of product ids.
 * @return
 *   XML data to be sent.
 */
function uc_importer_export($nids) {
  $data = array(
    'vocabularies' => array(),
    'categories' => array(),
    'manufacturers' => array(),
    'attributes' => array(),
    'classes' => array(),
    'products' => array(),
  );
  foreach ($nids as $nid) {
    $data['products'][] = $nid;
    $node = node_load($nid);
    if (uc_product_class_load($node->type)) {
      $data['classes'][] = $node->type;
    }
    if (module_exists('taxonomy')) {
      foreach ($node->taxonomy as $tid => $term) {
        $data['vocabularies'][] = $term->vid;
        foreach (taxonomy_get_parents_all($term->tid) as $parent) {

          // First $parent is $term, so no special case needed
          $data['categories'][] = $parent->tid;
        }
        if (module_exists('uc_manufacturer') && $term->vid == variable_get('uc_manufacturer_vid', 0)) {
          $data['manufacturers'][] = $tid;
        }
      }
    }
    if (module_exists('uc_attribute')) {
      $data['attributes'] += array_keys(uc_product_get_attributes($nid));
    }
  }
  foreach ($data as $type => $ids) {
    $data[$type] = array_unique($ids);
  }
  drupal_set_message('<pre>' . print_r($data, true) . '</pre>');
  $xml = '<?xml version="1.0" encoding="utf-8" ?>' . "\n";
  $xml .= '<store xmlns="http://www.ubercart.org" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.ubercart.org http://www.ubercart.org/files/store.xsd">';
  if (is_array($data['vocabularies']) && !empty($data['categories'])) {
    $xml .= _uc_importer_export_vocabularies($data['vocabularies']);
  }
  if (is_array($data['categories']) && !empty($data['categories'])) {
    $xml .= _uc_importer_export_categories($data['categories']);
  }
  if (is_array($data['manufacturers']) && !empty($data['manufacturers'])) {
    $xml .= _uc_importer_export_manufacturers($data['manufacturers']);
  }
  if (is_array($data['attributes']) && !empty($data['attributes'])) {
    $xml .= _uc_importer_export_attributes($data['attributes']);
  }
  if (is_array($data['classes']) && !empty($data['classes'])) {
    $xml .= _uc_importer_export_classes($data['classes']);
  }
  if (is_array($data['products']) && !empty($data['products'])) {
    $xml .= _uc_importer_export_products($data['products']);
  }
  if (is_array($data['orders']) && !empty($data['orders'])) {
    $xml .= _uc_importer_export_orders($data['orders']);
  }
  $xml .= uc_importer_invoke('export', 'store', $nids);
  $xml .= '</store>';

  //drupal_set_message(htmlspecialchars($xml));
  return $xml;
}

/**
 * Export vocabularies as XML.
 */
function _uc_importer_export_vocabularies($vocabularies) {
  $xml .= '<vocabularies>';
  foreach ($vocabularies as $vid) {
    $xml .= '<vocabulary>';
    $vocabulary = taxonomy_get_vocabulary($vid);
    $xml .= '<id>' . $vocabulary->vid . '</id>';
    $xml .= '<name>' . htmlspecialchars($vocabulary->name, ENT_QUOTES, "UTF-8") . '</name>';
    $xml .= '<description>' . htmlspecialchars($vocabulary->description, ENT_QUOTES, "UTF-8") . '</description>';
    $xml .= '<relations>' . htmlspecialchars($vocabulary->relations, ENT_QUOTES, "UTF-8") . '</relations>';
    $xml .= '<hierarchy>' . $vocabulary->hierarchy . '</hierarchy>';
    $xml .= '<multiple>' . $vocabulary->multiple . '</multiple>';
    $xml .= '<required>' . $vocabulary->required . '</required>';
    $xml .= '<tags>' . $vocabulary->tags . '</tags>';
    $xml .= '<weight>' . $vocabulary->weight . '</weight>';
    foreach ($vocabulary->nodes as $type) {
      $xml .= '<nodes>' . $type . '</nodes>';
    }
    $xml .= uc_importer_invoke('export', 'vocabulary', $vid);
    $xml .= '</vocabulary>';
  }
  $xml .= '</vocabularies>';
  return $xml;
}

/**
 * Export categories as XML.
 */
function _uc_importer_export_categories($categories) {
  $xml .= '<categories>';
  foreach ($categories as $tid) {
    $xml .= '<category>';
    $term = taxonomy_get_term($tid);
    $parents = taxonomy_get_parents($tid);
    $xml .= '<id>' . $term->tid . '</id>';
    $xml .= '<vid>' . $term->vid . '</vid>';
    $xml .= '<name>' . htmlspecialchars($term->name, ENT_QUOTES, "UTF-8") . '</name>';
    $xml .= '<description>' . htmlspecialchars($term->description, ENT_QUOTES, "UTF-8") . '</description>';
    foreach ($parents as $parent) {
      $xml .= '<parent>' . $parent->tid . '</parent>';
    }
    $xml .= uc_importer_invoke('export', 'category', $tid);
    $xml .= '</category>';
  }
  $xml .= '</categories>';
  return $xml;
}

/**
 * Export manufacturers as XML.
 */
function _uc_importer_export_manufacturers($manufacturers) {
  $xml = '<manufacturers>';
  foreach ($manufacturers as $tid) {
    $manufacturer = uc_manufacturer_load($tid);
    $xml .= '<manufacturer>';
    $xml .= '<id>' . $manufacturer->tid . '</id>';
    $xml .= '<name>' . htmlspecialchars($manufacturer->name, ENT_QUOTES, "UTF-8") . '</name>';
    $xml .= isset($manufacturer->url) && !empty($manufacturer->url) ? '<url>' . $manufacturer->url . '</url>' : '';
    $xml .= isset($manufacturer->phone_no) && !empty($manufacturer->phone_no) ? '<phone_no>' . $manufacturer->phone_no . '</phone_no>' : '';
    $xml .= isset($manufacturer->fax_no) && !empty($manufacturer->fax_no) ? '<fax_no>' . $manufacturer->fax_no . '</fax_no>' : '';
    $xml .= uc_importer_invoke('export', 'manufacturer', $tid);
    $xml .= '</manufacturer>';
  }
  $xml .= '</manufacturers>';
  return $xml;
}

/**
 * Export product attributes as XML.
 */
function _uc_importer_export_attributes($attributes) {
  $xml = '<attributes>';
  foreach ($attributes as $aid) {
    $attribute = uc_attribute_load($aid);
    $xml .= '<attribute>';
    $xml .= '<id>' . $attribute->aid . '</id>';
    $xml .= '<name>' . htmlspecialchars($attribute->name, ENT_QUOTES, "UTF-8") . '</name>';
    $xml .= '<ordering>' . $attribute->ordering . '</ordering>';
    if (is_array($attribute->options) && count($attribute->options)) {
      $xml .= '<options>';
      foreach ($attribute->options as $option) {
        $xml .= '<option>';
        $xml .= '<id>' . $option->oid . '</id>';
        $xml .= '<name>' . htmlspecialchars($option->name, ENT_QUOTES, "UTF-8") . '</name>';
        $xml .= '<price>' . $option->price . '</price>';
        $xml .= '<weight>' . $option->weight . '</weight>';
        $xml .= '<ordering>' . $option->ordering . '</ordering>';
        $xml .= uc_importer_invoke('export', 'option', $option->oid);
        $xml .= '</option>';
      }
      $xml .= '</options>';
    }
    $xml .= uc_importer_invoke('export', 'attribute', $aid);
    $xml .= '</attribute>';
  }
  $xml .= '</attributes>';
  return $xml;
}

/**
 * Export product node types as XML.
 */
function _uc_importer_export_classes($classes) {
  $xml = '<classes>';
  foreach ($classes as $pcid) {
    $class = uc_product_class_load($pcid);
    $xml .= '<class>';
    $xml .= '<id>' . $class->pcid . '</id>';
    $xml .= '<name>' . htmlspecialchars($class->name, ENT_QUOTES, "UTF-8") . '</name>';
    $xml .= '<description>' . htmlspecialchars($class->description, ENT_QUOTES, "UTF-8") . '</description>';
    $xml .= uc_importer_invoke('export', 'class', $pcid);
    $xml .= '</class>';
  }
  $xml .= '</classes>';
  return $xml;
}

/**
 * Export products as XML.
 */
function _uc_importer_export_products($products) {
  $xml = '<products>';
  foreach ($products as $nid) {
    $xml .= '<product>';
    $product = node_load($nid);
    $xml .= '<unique_hash>' . $product->unique_hash . '</unique_hash>';
    $xml .= '<id>' . $product->nid . '</id>';
    $xml .= '<type>' . $product->type . '</type>';
    $xml .= '<name>' . htmlspecialchars($product->title, ENT_QUOTES, "UTF-8") . '</name>';
    $xml .= '<description>' . htmlspecialchars($product->body, ENT_QUOTES, "UTF-8") . '</description>';
    $xml .= '<model>' . htmlspecialchars($product->model, ENT_QUOTES, "UTF-8") . '</model>';
    if (module_exists('uc_manufacturer')) {
      $manufacturer = uc_product_get_manufacturer($product->nid);
      $xml .= isset($manufacturer->tid) ? '<manufacturer>' . htmlspecialchars($manufacturer->name, ENT_QUOTES, "UTF-8") . '</manufacturer>' : '';
    }
    $xml .= isset($product->list_price) ? '<list_price>' . $product->list_price . '</list_price>' : '';
    $xml .= isset($product->cost) ? '<cost>' . $product->cost . '</cost>' : '';
    $xml .= '<sell_price>' . $product->sell_price . '</sell_price>';
    $xml .= '<weight>' . $product->weight . '</weight>';
    $xml .= '<weight_units>' . $product->weight_units . '</weight_units>';
    $xml .= '<length>' . $product->length . '</length>';
    $xml .= '<width>' . $product->width . '</width>';
    $xml .= '<height>' . $product->height . '</height>';
    $xml .= '<length_units>' . $product->length_units . '</length_units>';
    $xml .= '<pkg_qty>' . $product->pkg_qty . '</pkg_qty>';
    $xml .= '<default_qty>' . $product->default_qty . '</default_qty>';
    $xml .= '<shippable>' . $product->shippable . '</shippable>';
    if (isset($product->field_image_cache) && file_exists($product->field_image_cache[0]['filepath'])) {
      foreach ($product->field_image_cache as $image) {
        $xml .= '<image>';
        $xml .= '<path>' . $GLOBALS['base_url'] . '/' . dirname($image['filepath']) . '/' . rawurlencode(basename($image['filepath'])) . '</path>';
        if (!empty($image['alt'])) {
          $xml .= '<alt>' . $image['alt'] . '</alt>';
        }
        if (!empty($image['title'])) {
          $xml .= '<title>' . $image['title'] . '</title>';
        }
        $xml .= '</image>';
      }
    }
    if (module_exists('content')) {
      $type = content_types($product->type);
      if (count($type['fields'])) {
        $field_xml = '';
        foreach ($type['fields'] as $field) {
          if ($field['field_name'] != 'field_image_cache') {
            $node_field = isset($product->{$field}['field_name']) ? $product->{$field}['field_name'] : array();
            if (count($node_field)) {
              $field_xml .= '<field>';
              $field_xml .= '<name>' . $field['field_name'] . '</name>';
              foreach ($node_field as $columns) {
                $field_xml .= '<delta>';
                foreach ($columns as $name => $value) {
                  $field_xml .= '<' . $name . '>' . $value . '</' . $name . '>';
                }
                $field_xml .= '</delta>';
              }
              $field_xml .= '</field>';
            }
          }
        }
        if ($field_xml) {
          $xml .= "<fields>{$field_xml}</fields>";
        }
      }
    }
    if (module_exists('taxonomy')) {
      $terms = taxonomy_node_get_terms($product->nid);
      $xml .= '<categories>';
      foreach ($terms as $term) {
        $xml .= '<category>';
        $xml .= '<id>' . $term->tid . '</id>';
        $xml .= '</category>';
      }
      $xml .= '</categories>';
    }
    if (module_exists('uc_attribute')) {
      $attributes = uc_product_get_attributes($product->nid);
      if (!empty($attributes)) {
        $xml .= '<attributes>';
        foreach ($attributes as $attribute) {
          $xml .= '<attribute>';
          $xml .= '<id>' . $attribute->aid . '</id>';
          $xml .= '<name>' . htmlspecialchars($attribute->name, ENT_QUOTES, "UTF-8") . '</name>';
          $xml .= '<ordering>' . $attribute->ordering . '</ordering>';
          $xml .= '<default_option>' . $attribute->default_option . '</default_option>';
          if (!empty($attribute->options)) {
            $xml .= '<options>';
            foreach ($attribute->options as $option) {
              $xml .= '<option>';
              $xml .= '<id>' . $option->oid . '</id>';
              $xml .= '<name>' . htmlspecialchars($option->name, ENT_QUOTES, "UTF-8") . '</name>';
              $xml .= '<price>' . $option->price . '</price>';
              $xml .= '<weight>' . $option->weight . '</weight>';
              $xml .= '<ordering>' . $option->ordering . '</ordering>';
              $xml .= uc_importer_invoke('export', 'product-option', $product->nid, $option->oid);
              $xml .= '</option>';
            }
            $xml .= '</options>';
          }
          $xml .= uc_importer_invoke('export', 'product-attribute', $product->nid, $attribute->aid);
          $xml .= '</attribute>';
        }
        $xml .= '</attributes>';
      }
      $result = db_query("SELECT combination, model FROM {uc_product_adjustments} WHERE nid = %d", $product->nid);
      if (db_num_rows($result)) {
        $xml .= '<adjustments>';
        while ($adjustment = db_fetch_object($result)) {
          $xml .= '<adjustment>';
          $xml .= '<combination>' . htmlspecialchars($adjustment->combination, ENT_QUOTES, "UTF-8") . '</combination>';
          $xml .= '<model>' . htmlspecialchars($adjustment->model, ENT_QUOTES, "UTF-8") . '</model>';
          $xml .= uc_importer_invoke('export', 'adjustment', $adjustment, $product->nid);
          $xml .= '</adjustment>';
        }
        $xml .= '</adjustments>';
      }
    }
    $xml .= uc_importer_invoke('export', 'product', $product->nid);
    $xml .= '</product>';
  }
  $xml .= '</products>';
  return $xml;
}

/**
 * Export orders as XML.
 */
function _uc_importer_export_orders($orders) {
  $xml = '<orders>';
  foreach ($orders as $order_id) {
    $order = uc_order_load($order_id);
    if (!empty($order)) {
      $xml .= '<order>';
      $xml .= '<order_status>' . uc_order_status_data($order->order_status, 'title') . '</order_status>';
      $xml .= '<order_total>' . $order->order_total . '</order_total>';
      $xml .= '<primary_email>' . htmlspecialchars($order->primary_email, ENT_QUOTES, "UTF-8") . '</primary_email>';
      $xml .= '<delivery_first_name>' . htmlspecialchars($order->delivery_first_name, ENT_QUOTES, "UTF-8") . '</delivery_first_name>';
      $xml .= '<delivery_last_name>' . htmlspecialchars($order->delivery_last_name, ENT_QUOTES, "UTF-8") . '</delivery_last_name>';
      $xml .= '<delivery_phone>' . htmlspecialchars($order->delivery_phone, ENT_QUOTES, "UTF-8") . '</delivery_phone>';
      $xml .= '<delivery_company>' . htmlspecialchars($order->delivery_company, ENT_QUOTES, "UTF-8") . '</delivery_company>';
      $xml .= '<delivery_street1>' . htmlspecialchars($order->delivery_street1, ENT_QUOTES, "UTF-8") . '</delivery_street1>';
      $xml .= '<delivery_street2>' . htmlspecialchars($order->delivery_street2, ENT_QUOTES, "UTF-8") . '</delivery_street2>';
      $xml .= '<delivery_city>' . htmlspecialchars($order->delivery_city, ENT_QUOTES, "UTF-8") . '</delivery_city>';
      $xml .= '<delivery_zone>' . $order->delivery_zone . '</delivery_zone>';
      $xml .= '<delivery_zip>' . htmlspecialchars($order->delivery_zip, ENT_QUOTES, "UTF-8") . '</delivery_zip>';
      $xml .= '<delivery_country>' . $order->delivery_country . '</delivery_country>';
      $xml .= '<billing_first_name>' . htmlspecialchars($order->billing_first_name, ENT_QUOTES, "UTF-8") . '</billing_first_name>';
      $xml .= '<billing_last_name>' . htmlspecialchars($order->billing_last_name, ENT_QUOTES, "UTF-8") . '</billing_last_name>';
      $xml .= '<billing_phone>' . htmlspecialchars($order->billing_phone, ENT_QUOTES, "UTF-8") . '</billing_phone>';
      $xml .= '<billing_company>' . htmlspecialchars($order->billing_company, ENT_QUOTES, "UTF-8") . '</billing_company>';
      $xml .= '<billing_street1>' . htmlspecialchars($order->billing_street1, ENT_QUOTES, "UTF-8") . '</billing_street1>';
      $xml .= '<billing_street2>' . htmlspecialchars($order->billing_street2, ENT_QUOTES, "UTF-8") . '</billing_street2>';
      $xml .= '<billing_city>' . htmlspecialchars($order->billing_city, ENT_QUOTES, "UTF-8") . '</billing_city>';
      $xml .= '<billing_zone>' . $order->billing_zone . '</billing_zone>';
      $xml .= '<billing_zip>' . htmlspecialchars($order->billing_zip, ENT_QUOTES, "UTF-8") . '</billing_zip>';
      $xml .= '<billing_country>' . $order->billing_country . '</billing_country>';
      $xml .= '<payment_method>' . $order->payment_method . '</payment_method>';
      if (!empty($order->products)) {
        $xml .= '<products>';
        foreach ($order->products as $product) {
          $xml .= '<product>';
          $xml .= '<qty>' . $product->qty . '</qty>';
          $xml .= '<name>' . htmlspecialchars($product->title, ENT_QUOTES, "UTF-8") . '</name>';
          if ($product->manufacturer) {
            $xml .= '<manufacturer>' . htmlspecialchars($product->manufacturer, ENT_QUOTES, "UTF-8") . '</manufacturer>';
          }
          $xml .= '<model>' . htmlspecialchars($product->model, ENT_QUOTES, "UTF-8") . '</model>';
          $xml .= '<cost>' . $product->cost . '</cost>';
          $xml .= '<price>' . $product->price . '</price>';
          $xml .= '<weight>' . $product->weight . '</weight>';
          $xml .= '<data>' . htmlspecialchars($product->data, ENT_QUOTES, "UTF-8") . '</data>';
          $xml .= uc_importer_invoke('export', 'order-product', $order_id, $product->order_product_id);
          $xml .= '</product>';
        }
        $xml .= '</products>';
        $quote = $order->quote;
        $xml .= '<quote>';
        $xml .= '<method>' . $quote['method'] . '</method>';
        $xml .= '<accessorials>' . $quote['accessorials'] . '</accessorials>';
        $xml .= '<rate>' . $quote['rate'] . '</rate>';
        $xml .= '<quote_form>' . htmlspecialchars($quote['quote_form'], ENT_QUOTES, "UTF-8") . '</quote_form>';
        $xml .= uc_importer_invoke('export', 'quote', $order_id);
        $xml .= '</quote>';
        if (!empty($order->line_items)) {
          $xml .= '<line_items>';
          foreach ($order->line_items as $line_item) {
            $xml .= '<line_item>';
            $xml .= '<type>' . $line_item['type'] . '</type>';
            $xml .= '<title>' . htmlspecialchars($line_item['title'], ENT_QUOTES, "UTF-8") . '</title>';
            $xml .= '<amount>' . $line_item['amount'] . '</amount>';
            $xml .= '<weight>' . $line_item['weight'] . '</weight>';
            $xml .= uc_importer_invoke('export', 'line_item', $line_item->line_item_id);
            $xml .= '</line_item>';
          }
          $xml .= '</line_items>';
        }
      }
      $xml .= uc_importer_invoke('export', 'order', $order_id);
      $xml .= '</order>';
    }
  }
  $xml .= '</orders>';
  return $xml;
}

/**
 * Imports an XML document into the database.
 *
 * The script checks for objects that have the same names as those in the XML
 * document. If it finds a duplicate, it may replace that object with the XML,
 * create a new object with marker indicating its imported status, or abort the
 * importing of that particular object.
 *
 * @param $xml
 *   String of XML data. It should conform to the schema located at
 *   http://www.ubercart.org/files/store.xsd
 */
function uc_importer_import($xml) {
  include_once drupal_get_path('module', 'uc_store') . '/includes/simplexml.php';
  global $user, $active_db;
  $error = '';

  /* $data = new DOMDocument();
    $data->loadXML($xml);

    if (!$data) {
      $error = "Error: Could not load XML.";
    }
    else { */

  /* if (!($data->schemaValidate('http://www.ubercart.org/files/store.xsd'))) {
       $error = "Error: XML is not validated by schema.";
     }
     else { */
  $id_map = array(
    'vocabularies' => array(),
    'categories' => array(),
    'manufacturers' => array(),
    'attributes' => array(),
    'options' => array(),
    'classes' => array(),
    'products' => array(),
  );
  $store = new JSimpleXML();
  $store
    ->loadString($xml);
  if (module_exists('taxonomy')) {
    if (isset($store->document->vocabularies)) {
      foreach ($store->document->vocabularies[0]->vocabulary as $vocabulary_data) {
        $name = (string) $vocabulary_data->name[0]
          ->data();
        $result = db_query("SELECT vid FROM {vocabulary} WHERE name = '%s'", $name);
        if (db_num_rows($result) && variable_get('uc_importer_vocabulary_duplicates', UC_IMPORTER_DO_NOTHING) != UC_IMPORTER_INCREMENT) {
          $id_map['vocabularies'][(string) $vocabulary_data->id[0]
            ->data()] = db_result($result);
        }
        else {
          $vocab = array(
            'name' => html_entity_decode((string) $vocabulary_data->name[0]
              ->data(), ENT_QUOTES, "UTF-8"),
            'description' => html_entity_decode((string) $vocabulary_data->description[0]
              ->data(), ENT_QUOTES, "UTF-8"),
            'relations' => (int) $vocabulary_data->relations[0]
              ->data(),
            'hierarchy' => (int) $vocabulary_data->hierarchy[0]
              ->data(),
            'multiple' => (int) $vocabulary_data->multiple[0]
              ->data(),
            'required' => (int) $vocabulary_data->required[0]
              ->data(),
            'tags' => (int) $vocabulary_data->tags[0]
              ->data(),
            'weight' => (int) $vocabulary_data->weight[0]
              ->data(),
          );
          foreach ($vocabulary_data->nodes as $node_type) {
            $vocab['nodes'][(string) $node_type
              ->data()] = true;
          }
          taxonomy_save_vocabulary($vocab);
          $id_map['vocabularies'][(int) $vocabulary_data->id[0]
            ->data()] = db_result(db_query("SELECT id FROM {sequences} WHERE name = '{vocabulary}_vid'"));
        }
        module_invoke_all('xml_importer', 'vocabulary', taxonomy_get_vocabulary($id_map['vocabularies'][(int) $vocabulary_data->id[0]
          ->data()]), $vocabulary_data, $store, $id_map);
      }
    }
    $categories = array();
    if (isset($store->document->categories)) {
      $new_categories = array();
      foreach ($store->document->categories[0]->category as $category_data) {
        $name = (string) $category_data->name[0]
          ->data();
        $result = db_query("SELECT tid FROM {term_data} WHERE name = '%s'", $name);
        if (db_num_rows($result) && variable_get('uc_importer_category_duplicates', UC_IMPORTER_DO_NOTHING) != UC_IMPORTER_INCREMENT) {
          $id_map['categories'][(string) $category_data->id[0]
            ->data()] = db_result($result);
        }
        else {
          $tid = db_next_id('{term_data}_tid');
          $vid = isset($id_map['vocabularies'][(int) $category_data->vid[0]
            ->data()]) ? $id_map['vocabularies'][(int) $category_data->vid[0]
            ->data()] : variable_get('uc_catalog_vid', 0);
          $id_map['categories'][(string) $category_data->id[0]
            ->data()] = $tid;
          $new_categories[] = $tid;
          db_query("INSERT INTO {term_data} (tid, vid, name, description) VALUES (%d, %d, '%s', '%s')", $tid, $vid, html_entity_decode((string) $category_data->name[0]
            ->data(), ENT_QUOTES, "UTF-8"), html_entity_decode((string) $category_data->description[0]
            ->data(), ENT_QUOTES, "UTF-8"));
        }
      }
      foreach ($store->document->categories[0]->category as $category_data) {
        if (in_array($id_map['categories'][(string) $category_data->id[0]
          ->data()], $new_categories)) {
          $parent = 0;
          if (isset($category_data->parent)) {
            $parent = (string) $category_data->parent[0]
              ->data();
          }
          switch ($GLOBALS['db_type']) {
            case 'mysqli':
            case 'mysql':
              db_query("INSERT IGNORE INTO {term_hierarchy} (tid, parent) VALUES (%d, %d)", $id_map['categories'][(string) $category_data->id[0]
                ->data()], $id_map['categories'][$parent]);
              break;
            case 'pgsql':
              db_query("INSERT INTO {term_hierarchy} (tid, parent) VALUES (%d, %d)", $id_map['categories'][(string) $category_data->id[0]
                ->data()], $id_map['categories'][$parent]);
              break;
          }
        }
        module_invoke_all('xml_importer', 'category', taxonomy_get_term($id_map['categories'][(string) $category_data->id[0]
          ->data()]), $category_data, $store, $id_map);
      }
    }
    db_query("DELETE FROM {term_hierarchy} WHERE tid = parent");
  }
  if (module_exists('uc_manufacturer')) {
    if (isset($store->document->manufacturers)) {
      foreach ($store->document->manufacturers[0]->manufacturer as $manufacturer_data) {
        $manufacturer = new stdClass();
        foreach ($manufacturer_data
          ->children() as $datum) {
          $manufacturer->{$datum
            ->name()} = (string) $datum
            ->data();
        }
        $result = db_query("SELECT tid FROM {term_data} WHERE name LIKE '%s\\__' OR name LIKE '%s'", $manufacturer->name, $manufacturer->name);
        if ($tid = db_result($result)) {
          $manufacturer->tid = $tid;
          $id_map['manufacturers'][(int) $manufacturer->id] = $tid;
          if (in_array($tid, $new_categories)) {
            drupal_execute('taxonomy_form_term', (array) $manufacturer, variable_get('uc_manufacturer_vid', 0), array(
              'tid' => $tid,
            ));
          }
          else {
            switch (variable_get('uc_importer_category_duplicates', UC_IMPORTER_DO_NOTHING)) {
              case UC_IMPORTER_REPLACE:
                drupal_execute('taxonomy_form_term', (array) $manufacturer, variable_get('uc_manufacturer_vid', 0), array(
                  'tid' => $tid,
                ));
                break;
              case UC_IMPORTER_INCREMENT:
                $manufacturer->name .= '_' . db_num_rows($result);
                drupal_execute('taxonomy_form_term', (array) $manufacturer, variable_get('uc_manufacturer_vid', 0));
                break;
            }
          }
        }
        else {
          drupal_execute('taxonomy_form_term', (array) $manufacturer, variable_get('uc_manufacturer_vid', 0));
          $id_map['manufacturers'][(int) $manufacturer->id] = db_result(db_query("SELECT id FROM {sequences} WHERE name = '{term_data}_tid'"));
        }
        module_invoke_all('xml_importer', 'manufacturer', uc_manufacturer_load($id_map['manufacturers'][(int) $manufacturer->id]), $manufacturer_data, $store, $id_map);
      }
    }
  }
  if (module_exists('uc_attribute')) {
    if (isset($store->document->attributes)) {
      foreach ($store->document->attributes[0]->attribute as $attribute_data) {
        $attribute = new stdClass();
        $attribute->name = html_entity_decode((string) $attribute_data->name[0]
          ->data(), ENT_QUOTES, "UTF-8");
        $attribute->ordering = isset($attribute_data->ordering) ? (int) $attribute_data->ordering[0]
          ->data() : 0;
        $result = db_query("SELECT aid FROM {uc_attributes} WHERE name LIKE '%s\\__' OR name LIKE '%s'", $attribute->name, $attribute->name);
        if ($aid = db_result($result)) {
          if (variable_get('uc_importer_attribute_duplicates', UC_IMPORTER_DO_NOTHING) == UC_IMPORTER_INCREMENT) {
            $attribute->name .= '_' . db_num_rows($result);
            drupal_execute('uc_attribute_form', (array) $attribute);
          }
        }
        else {
          drupal_execute('uc_attribute_form', (array) $attribute);
          $aid = db_result(db_query("SELECT aid FROM {uc_attributes} WHERE name = '%s'", $attribute->name));
        }
        if ($aid) {
          $id_map['attributes'][(string) $attribute_data->id[0]
            ->data()] = $aid;
          $attribute->options = array();
          if (isset($attribute_data->options)) {
            foreach ($attribute_data->options[0]->option as $option_data) {
              $option = new stdClass();
              $option->name = html_entity_decode((string) $option_data->name[0]
                ->data(), ENT_QUOTES, "UTF-8");
              $option->price = isset($option_data->price) ? (double) $option_data->price[0]
                ->data() : 0;
              $option->weight = isset($option_data->weight) ? (double) $option_data->weight[0]
                ->data() : 0;
              $option->ordering = isset($option_data->ordering) ? (int) $option_data->ordering[0]
                ->data() : 0;
              $result = db_query("SELECT oid FROM {uc_attribute_options} WHERE aid = %d AND (name LIKE '%s\\__' OR name LIKE '%s')", $aid, $option->name, $option->name);
              if ($oid = db_result($result)) {
                switch (variable_get('uc_importer_attribute_duplicates', UC_IMPORTER_DO_NOTHING)) {
                  case UC_IMPORTER_INCREMENT:
                    $option->name .= '_' . db_num_rows($result);
                    drupal_execute('uc_attribute_option_form', (array) $option, $aid);
                    $id_map['options'][(string) $option_data->id[0]
                      ->data()] = db_result(db_query("SELECT MAX(oid) FROM {uc_attribute_options}"));
                    break;
                  case UC_IMPORTER_REPLACE:
                    drupal_execute('uc_attribute_option_form', (array) $option, $aid, $oid);
                  case UC_IMPORTER_DO_NOTHING:
                    $id_map['options'][(string) $option_data->id[0]
                      ->data()] = $oid;
                    break;
                }
              }
              else {
                drupal_execute('uc_attribute_option_form', (array) $option, $aid);
                $id_map['options'][(string) $option_data->id[0]
                  ->data()] = db_result(db_query("SELECT MAX(oid) FROM {uc_attribute_options}"));
              }
              module_invoke_all('xml_importer', 'option', uc_attribute_option_load($id_map['options'][(string) $option_data->id[0]
                ->data()]), $option_data, $store, $id_map);
            }
          }
        }
        module_invoke_all('xml_importer', 'attribute', uc_attribute_load($id_map['attributes'][(string) $attribute_data->id[0]
          ->data()]), $attribute_data, $store, $id_map);
      }
    }
  }
  $class = 'class';

  // keyword workaround
  if (isset($store->document->classes)) {
    $types = module_invoke_all('node_info');
    foreach ($store->document->classes[0]->{$class} as $class_data) {
      $class = new stdClass();
      $class->pcid = (string) $class_data->id[0]
        ->data();
      $class->name = (string) $class_data->name[0]
        ->data();
      if (isset($class_data->description)) {
        $class->description = (string) $class_data->description[0]
          ->data();
      }
      $result = db_query("SELECT pcid FROM {uc_product_classes} WHERE pcid = '%s'", $class->pcid);
      if ($pcid = db_result($result)) {
        switch (variable_get('uc_importer_class_duplicates', UC_IMPORTER_DO_NOTHING)) {
          case UC_IMPORTER_REPLACE:
            drupal_execute('uc_product_class_form', (array) $class, $class->pcid);
            break;
          case UC_IMPORTER_INCREMENT:
            drupal_execute('uc_product_class_form', (array) $class);
            break;
        }
      }
      else {
        drupal_execute('uc_product_class_form', (array) $class, $class->pcid);
      }
      module_invoke('xml_importer', 'class', $types[(string) $class_data->id[0]
        ->data()], $class_data, $store, $id_map);
    }
  }
  if (isset($store->document->products)) {
    foreach ($store->document->products[0]->product as $product_data) {
      $product = new stdClass();

      //watchdog('importer', '<pre>'. print_r($product_data->unique_hash[0]->data(), true) .'</pre>');
      if (!isset($product_data->unique_hash)) {
        $product_data
          ->addChild('unique_hash', md5((string) $product_data->model[0]
          ->data() . (string) $product_data->list_price[0]
          ->data() . (string) $product_data->cost[0]
          ->data() . (string) $product_data->sell_price[0]
          ->data() . (string) $product_data->weight[0]
          ->data() . (string) $product_data->weight_units[0]
          ->data() . (string) $product_data->default_qty[0]
          ->data() . time()), $product_data
          ->level() + 1);
      }

      // Try by unique_hash...
      if (!($nid = db_result(db_query("SELECT nid FROM {uc_products} WHERE unique_hash LIKE '%s'", (string) $product_data->unique_hash[0]
        ->data())))) {

        // ...else try by product model.
        $nid = db_result(db_query("SELECT nid FROM {uc_products} WHERE model LIKE '%s'", (string) $product_data->model[0]
          ->data()));
      }
      if ($nid) {
        switch (variable_get('uc_importer_product_duplicates', UC_IMPORTER_DO_NOTHING)) {
          case UC_IMPORTER_REPLACE:
            $product->nid = $nid;
            $product->revision = true;
            $product->unique_hash = db_result(db_query("SELECT unique_hash FROM {uc_products} WHERE nid = %d", $nid));
            $id_map['products'][(string) $product_data->id[0]
              ->data()] = $nid;
            break;
          case UC_IMPORTER_INCREMENT:
            unset($product_data->unique_hash);
            $id_map['products'][(string) $product_data->id[0]
              ->data()] = $nid;
            break;
          case UC_IMPORTER_DO_NOTHING:
            $product->nid = $nid;
            $id_map['products'][(string) $product_data->id[0]
              ->data()] = $nid;
            continue 2;
        }
      }
      else {
        $product->unique_hash = (string) $product_data->unique_hash[0]
          ->data();
      }
      $product->type = (string) $product_data->type[0]
        ->data();
      $product->uid = $user->uid;
      $product->log = t('Imported product from XML.');
      $product->name = $user->name;
      $product->status = 1;
      $product->format = filter_resolve_format(FILTER_FORMAT_DEFAULT);
      if (module_exists('uc_catalog')) {
        if (isset($product_data->categories) && count($product_data->categories) > 0) {
          foreach ($product_data->categories[0]->category as $category_data) {
            $product->taxonomy[] = $id_map['categories'][(string) $category_data->id[0]
              ->data()];
          }
        }
      }
      $product->title = html_entity_decode((string) $product_data->name[0]
        ->data(), ENT_QUOTES, "UTF-8");
      $product->body = html_entity_decode((string) $product_data->description[0]
        ->data(), ENT_QUOTES, "UTF-8");
      $product->teaser = node_teaser($product->body, $product->format);
      $product->model = html_entity_decode((string) $product_data->model[0]
        ->data(), ENT_QUOTES, "UTF-8");

      /* if (module_exists('uc_manufacturer') && $manufacturer = variable_get('uc_manufacturer_vid', 0)) {
           $product->taxonomy['tags'][$manufacturer] = html_entity_decode((string)$product_data->manufacturer[0]->data(), ENT_QUOTES, "UTF-8");
         } */
      $product->list_price = (double) $product_data->list_price[0]
        ->data();
      $product->cost = (double) $product_data->cost[0]
        ->data();
      $product->sell_price = (double) $product_data->sell_price[0]
        ->data();
      $product->weight = (double) $product_data->weight[0]
        ->data();
      $product->weight_units = isset($product_data->weight_units) ? (string) $product_data->weight_units[0]
        ->data() : variable_get('uc_weight_unit', 'lb');
      if (isset($product_data->length, $product_data->width, $product_data->height)) {
        $product->length = (double) $product_data->length[0]
          ->data();
        $product->width = (double) $product_data->width[0]
          ->data();
        $product->height = (double) $product_data->height[0]
          ->data();
        $product->length_units = isset($product_data->length_units) ? (string) $product_data->length_units[0]
          ->data() : variable_get('uc_length_unit', 'in');
      }
      if (isset($product_data->pkg_qty)) {
        $product->pkg_qty = (int) $product_data->pkg_qty[0]
          ->data();
      }
      if (isset($product_data->default_qty)) {
        $product->default_qty = (int) $product_data->default_qty[0]
          ->data();
      }
      if (isset($product_data->shippable)) {
        $product->shippable = (int) $product_data->shippable[0]
          ->data();
      }
      $i = 0;
      if (module_exists('imagefield')) {
        if (isset($product_data->image)) {
          foreach ($product_data->image as $image) {
            $image_path = (string) $image->path[0]
              ->data();
            $path_info = pathinfo($image_path);
            $image_field = content_fields('field_image_cache', $product->type);
            $path = $image_field['widget']['image_path'];
            if (!($local_path = file_create_path($path))) {
              $local_path = file_check_directory($path, FILE_CREATE_DIRECTORY);
            }
            $local_path .= '/' . rawurldecode(basename($image_path));
            $size = 0;
            if (!file_exists($local_path)) {
              $input = fopen($image_path, 'rb');
              $output = fopen($local_path, 'wb');
              while ($data = fread($input, 1024)) {
                $size += fwrite($output, $data, 1024);
              }
              fclose($input);
              fclose($output);
            }
            else {
              $size = filesize($local_path);
            }
            $product->field_image_cache[$i] = array(
              'fid' => file_exists($local_path) ? db_result(db_query("SELECT fid FROM {files} WHERE nid = %d AND filepath = '%s'", $nid, $local_path)) : 'upload',
              'title' => isset($image->title) ? html_entity_decode((string) $image->title[0]
                ->data(), ENT_QUOTES, "UTF-8") : '',
              'alt' => isset($image->alt) ? html_entity_decode((string) $image->alt[0]
                ->data(), ENT_QUOTES, "UTF-8") : '',
              'filename' => basename($image_path),
              'filepath' => $local_path,
              'filesize' => $size,
              'filemime' => 'image/' . $path_info['extension'],
            );
            $i++;
          }
        }
      }
      if (isset($product_data->fields)) {
        $fields = array();
        foreach ($product_data->fields[0]->field as $field_data) {
          foreach ($field_data->delta as $delta) {
            $columns = array();
            foreach ($delta
              ->children() as $value_data) {
              $columns[$value_data
                ->name()] = html_entity_decode((string) $value_data
                ->data(), ENT_QUOTES, "UTF-8");
            }
            $field_name = html_entity_decode((string) $field_data->name[0]
              ->data(), ENT_QUOTES, "UTF-8");
            if (!is_array($product->{$field_name})) {
              $product->{$field_name} = array();
            }
            array_push($product->{$field_name}, $columns);
          }
        }
      }

      //watchdog('importer', '<pre>'. print_r($product_data, true) .'</pre>');

      //watchdog('importer', '<pre>'. print_r($product, true) .'</pre>');
      node_save($product);
      if (!isset($product->nid)) {
        $product->nid = db_result(db_query("SELECT id FROM {sequences} WHERE name = '{node}_nid'"));
      }
      $id_map['products'][(string) $product_data->id[0]
        ->data()] = $product->nid;
      if (module_exists('uc_attribute')) {
        $attr_replace = array();
        $attr_values = array();
        $opt_replace = array();
        $opt_values = array();
        if (isset($product_data->attributes)) {
          foreach ($product_data->attributes[0]->attribute as $attribute_data) {
            if (!isset($id_map['attributes'][(string) $attribute_data->id[0]
              ->data()])) {
              $attribute = new stdClass();
              $attribute->name = html_entity_decode((string) $attribute_data->name[0]
                ->data(), ENT_QUOTES, "UTF-8");
              $attribute->ordering = isset($attribute_data->ordering) ? (int) $attribute_data->ordering[0]
                ->data() : 0;
              drupal_execute('uc_attribute_form', (array) $attribute);
              $id_map['attributes'][(string) $attribute_data->id[0]
                ->data()] = db_result(db_query("SELECT aid FROM {uc_attributes} WHERE name = '%s'", $attribute->name));
            }
            $attr_replace[] = '%d,%d,%d,%d';
            $attr_values[] = $product->nid;
            $attr_values[] = $id_map['attributes'][(string) $attribute_data->id[0]
              ->data()];
            $attr_values[] = isset($attribute_data->ordering) ? (int) $attribute_data->ordering[0]
              ->data() : 0;
            if (isset($attribute_data->options)) {
              foreach ($attribute_data->options[0]->option as $option_data) {
                if (!isset($id_map['options'][(string) $option_data->id[0]
                  ->data()])) {
                  $option = new stdClass();
                  $option->name = html_entity_decode((string) $option_data->name[0]
                    ->data(), ENT_QUOTES, "UTF-8");
                  $option->price = (double) $option_data->price[0]
                    ->data();
                  $option->weight = (double) $option_data->weight[0]
                    ->data();
                  $option->ordering = isset($option_data->ordering) ? (int) $option_data->ordering[0]
                    ->data() : 0;
                  drupal_execute('uc_attribute_option_form', (array) $option, $id_map['attributes'][(string) $attribute_data->id[0]
                    ->data()]);
                  $id_map['options'][(string) $option_data->id[0]
                    ->data()] = db_result(db_query("SELECT MAX(oid) FROM {uc_attribute_options}"));
                }
                $opt_replace[] = '%d,%d,%f,%f,%d';
                $opt_values[] = $product->nid;
                $opt_values[] = $id_map['options'][(string) $option_data->id[0]
                  ->data()];
                $opt_values[] = (double) $option_data->price[0]
                  ->data();
                $opt_values[] = (double) $option_data->weight[0]
                  ->data();
                $opt_values[] = isset($option_data->ordering) ? (int) $option_data->ordering[0]
                  ->data() : 0;
                module_invoke_all('xml_importer', 'product-option', $product->nid, $option_data, $store, $id_map);
              }
            }
            $default_option = isset($attribute_data->default_option) ? (string) $attribute_data->default_option[0]
              ->data() : $attribute_data->options->option[0]->id[0]
              ->data();
            $attr_values[] = $id_map['options'][$default_option];
            module_invoke_all('xml_importer', 'product-attribute', $product->nid, $attribute_data, $store, $id_map);
          }
        }
        if (count($attr_values)) {
          db_query("DELETE FROM {uc_product_attributes} WHERE nid = %d", $product->nid);
          db_query("INSERT INTO {uc_product_attributes} (nid, aid, ordering, default_option) VALUES (" . implode('),(', $attr_replace) . ")", $attr_values);
        }
        if (count($opt_values)) {
          db_query("DELETE FROM {uc_product_options} WHERE nid = %d", $product->nid);
          db_query("INSERT INTO {uc_product_options} (nid, oid, price, weight, ordering) VALUES (" . implode('),(', $opt_replace) . ")", $opt_values);
        }
        $adjustments = array(
          'nid' => $product->nid,
          'default' => $product->model,
          'body' => array(),
        );
        if (isset($product_data->adjustments)) {
          foreach ($product_data->adjustments[0]->adjustment as $adjustment_data) {
            $combination = array();
            $old_combo = unserialize(html_entity_decode((string) $adjustment_data->combination[0]
              ->data(), ENT_QUOTES, "UTF-8"));
            if (is_array($old_combo)) {
              foreach ($old_combo as $aid => $oid) {
                $combination[$id_map['attributes'][$aid]] = $id_map['options'][$oid];
              }
              $adjustment = array(
                'combo_array' => serialize($combination),
                'model' => html_entity_decode((string) $adjustment_data->model[0]
                  ->data(), ENT_QUOTES, "UTF-8"),
              );
              $adjustments['body'][] = $adjustment;
              module_invoke_all('xml_importer', 'adjustment', $adjustment, $adjustment_data, $store, $id_map);
            }
          }
        }
        if (count($adjustments['body'])) {
          uc_product_adjustments_form_submit('uc_product_adjustments_form', $adjustments);
        }
      }

      // Product-by-product hook call to try and improve efficency if 'uc_import' hook
      module_invoke_all('xml_importer', 'product', $product, $product_data, $store, $id_map);
    }

    // General hook call if data to import isn't too Product specific
    module_invoke_all('xml_importer', 'store', $store, $id_map);
  }

  //}

  //drupal_set_message('<pre>'. print_r($id_map, true) .'</pre>');
  cache_clear_all();

  //}
  if ($error) {
    drupal_set_message($error, 'error');
  }
}

/**
 * Import XML data from a file.
 *
 * Callback for file_scan_directory.
 *
 * @see uc_importer_import_form_submit
 */
function uc_importer_directory_parse($filename) {
  if ($xml = file_get_contents($filename)) {
    uc_importer_import($xml);
  }
}

/**
 * Specific order importer for a certain osCommerce site.
 */
function uc_importer_orders($xml) {
  $id_map = array(
    'statuses' => array(
      1 => 'pending',
      20 => 'in_checkout',
      30 => 'pending',
      40 => 'processing',
      50 => 'processing',
      60 => 'completed',
      70 => 'completed',
      -20 => 'canceled',
      -10 => 'in_checkout',
    ),
    'countries' => array(
      38 => 124,
      // Canada
      138 => 484,
      // Mexico
      223 => 840,
      // United States
      240 => 158,
      // Taiwan
      241 => 826,
      // United Kingdom
      242 => 276,
    ),
    'orders' => array(),
    'products' => array(),
  );
  $store = simplexml_load_string($xml);
  foreach ($store->orders->order as $order_data) {
    $uid = 0;
    $user = user_load(array(
      'mail' => (string) $order_data->primary_email,
    ));
    if ($user) {
      $uid = $user->uid;
    }
    $status = $id_map['statuses'][$order_data->order_status];
    $order = uc_order_new($uid, $status);
    $order_fields = array(
      'order_status',
      'order_total',
      'primary_email',
      'delivery_first_name',
      'delivery_last_name',
      'delivery_phone',
      'delivery_company',
      'delivery_street1',
      'delivery_street2',
      'delivery_city',
      'delivery_zone',
      'delivery_postal_code',
      'billing_first_name',
      'billing_last_name',
      'billing_phone',
      'billing_company',
      'billing_street1',
      'billing_street2',
      'billing_city',
      'billing_zone',
      'billing_postal_code',
      'payment_method',
      'modified',
      'created',
    );
    foreach ($order_fields as $field) {
      $order->{$field} = (string) $order_data->{$field};
    }
    $order->delivery_country = $id_map['countries'][(string) $order_data->delivery_country];
    $order->billing_country = $id_map['countries'][(string) $order_data->billing_country];
    db_query("UPDATE {uc_orders} SET uid = %d, order_status = '%s', order_total = %f, primary_email = '%s', " . "delivery_first_name = '%s', delivery_last_name = '%s', delivery_phone = '%s', " . "delivery_company = '%s', delivery_street1 = '%s', delivery_street2 = '%s', " . "delivery_city = '%s', delivery_zone = %d, delivery_postal_code = '%s', delivery_country = %d, " . "billing_first_name = '%s', billing_last_name = '%s', billing_phone = '%s', " . "billing_company = '%s', billing_street1 = '%s', billing_street2 = '%s', " . "billing_city = '%s', billing_zone = %d, billing_postal_code = '%s', billing_country = %d, " . "payment_method = '%s', modified = %d, created = %d WHERE order_id = %d", $order->uid, $order->order_status, $order->order_total, $order->primary_email, $order->delivery_first_name, $order->delivery_last_name, $order->delivery_phone, $order->delivery_company, $order->delivery_street1, $order->delivery_street2, $order->delivery_city, $order->delivery_zone, $order->delivery_postal_code, is_null($order->delivery_country) || $order->delivery_country == 0 ? variable_get('uc_store_country', 840) : $order->delivery_country, $order->billing_first_name, $order->billing_last_name, $order->billing_phone, $order->billing_company, $order->billing_street1, $order->billing_street2, $order->billing_city, $order->billing_zone, $order->billing_postal_code, is_null($order->billing_country) || $order->billing_country == 0 ? variable_get('uc_store_country', 840) : $order->billing_country, $order->payment_method, $order->modified, $order->created, $order->order_id);
    foreach ($order_data->products->product as $product_data) {
      $product = new stdClass();
      $product->nid = 0;
      $product_fields = array(
        'qty',
        'name',
        'manufacturer',
        'model',
        'cost',
        'price',
        'weight',
      );
      foreach ($product_fields as $field) {
        $product->{$field} = (string) $product_data->{$field};
      }
      $product->data = unserialize((string) $product_data->data);
      uc_order_product_save($order->order_id, $product);
    }
    $comments_types = array();
    $comments_values = array();
    foreach ($order->comments->comment as $comment) {
      $comments_types[] = "(%d,%d,'%s',%d,%d,%d)";
      $comments_values[] = $order->order_id;
      $commenter = user_load(array(
        'name' => (string) $comment->user,
      ));
      if ($commenter) {
        $comments_values[] = $commenter->uid;
      }
      else {
        $comments_values[] = 0;
      }
      $comments_values[] = (string) $comment->message;
      $comments_values[] = (string) $comment->order_status;
      $comments_values[] = (int) $comment->notified;
      $comments_values[] = (int) $comment->created;
    }
    if (count($comments_values)) {
      db_query("INSERT INTO {uc_order_comments} (order_id, uid, message, order_status, notified, created) VALUES " . implode(',', $comments_types), $comments_values);
    }
    $comments_types = array();
    $comments_values = array();
    foreach ($order->admin_comments->comment as $comment) {
      $comments_types[] = "(%d,%d,'%s',%d)";
      $comments_values[] = $order->order_id;
      $commenter = user_load(array(
        'name' => (string) $comment->user,
      ));
      if ($commenter) {
        $comments_values[] = $commenter->uid;
      }
      else {
        $comments_values[] = 0;
      }
      $comments_values[] = (string) $comment->message;
      $comments_values[] = (int) $comment->created;
    }
    if (count($comments_values)) {
      db_query("INSERT INTO {uc_order_admin_comments} (order_id, uid, message, created) VALUES " . implode(',', $comments_types), $comments_values);
    }
  }
}

/**
 * Invoke hook_xml_exporter().
 *
 * @return
 *   Concatenated XML data from each module's implementation.
 */
function uc_importer_invoke() {
  $args = func_get_args();
  $direction = array_shift($args);
  if ($direction = 'export') {
    $output = '';
    foreach (module_list() as $module) {
      if (module_hook($module, 'xml_exporter')) {

        // Can't use module_invoke because of the array of arguments
        $output .= call_user_func_array($module . '_xml_exporter', $args);
      }
    }
    return $output;
  }
}

Functions

Namesort descending Description
uc_importer_admin_settings Configure the importer behaviour when handling duplicate objects.
uc_importer_admin_settings_submit Submit handler for uc_importer_admin_settings().
uc_importer_admin_settings_validate Validation handler for uc_importer_admin_settings().
uc_importer_directory_parse Import XML data from a file.
uc_importer_export Constructs the XML representation of the store from the ids given.
uc_importer_export_buffer_form Form to collect the id numbers of all the store components to be exported.
uc_importer_export_buffer_form_submit Submit handler for uc_importer_export_buffer_form().
uc_importer_export_form Choose the nodes to export.
uc_importer_export_form_submit Submit handler for uc_importer_form().
uc_importer_export_page Wrapper function to generate a page to hold the export form.
uc_importer_import Imports an XML document into the database.
uc_importer_import_form Upload form for an XML file to be imported.
uc_importer_import_form_submit Submit function for uc_importer_import_form().
uc_importer_import_page Wrapper function to generate a page to hold the import form.
uc_importer_invoke Invoke hook_xml_exporter().
uc_importer_menu Implementation of hook_menu().
uc_importer_orders Specific order importer for a certain osCommerce site.
uc_importer_perm Implementation of hook_perm().
_uc_importer_export_attributes Export product attributes as XML.
_uc_importer_export_categories Export categories as XML.
_uc_importer_export_classes Export product node types as XML.
_uc_importer_export_manufacturers Export manufacturers as XML.
_uc_importer_export_orders Export orders as XML.
_uc_importer_export_products Export products as XML.
_uc_importer_export_vocabularies Export vocabularies as XML.

Constants

Namesort descending Description
UC_IMPORTER_DO_NOTHING Do not save objects if the database already contains their names.
UC_IMPORTER_INCREMENT Append '_#' to the names of objects already in the database.
UC_IMPORTER_REPLACE Replace objects if the database already contains their names.