简体   繁体   中英

CSV Import/Export problems in Magento

Ok, so I managed to export my categories into a csv-file by following a set of instructions on justcode.in. I want to import my CSV back to a new installation of Magento.

I am running Magento 1.9.2.2 When I try to run the profile, it finds my CSV-file and loads it, but it throws me this error.

Error message,

<br /> <b>Fatal error</b>: Call to undefined method ImpCat_Catalog_Model_Convert_Adapter_Category::getStoreById() in <b>/var/www/public/secondstore/app/code/local/ImpCat/Catalog/Model/Convert/Adapter/Category.php</b> on line <b>32</b><br />

The CSV file is structured in this matter,

store;categories;is_active;meta_title;meta_keywords;meta_description;include_in_menu;is_anchor;description

Then I created config.xml at app\\code\\local\\ImpCat\\Catalog\\etc\\config.xml. this file looks like this,

<?xml version="1.0"?>
<config>
 <global>
  <models>
   <catalog>
    <rewrite>
     <convert_adapter_category>ImpCat_Catalog_Model_Convert_Adapter_Category</convert_adapter_category>
    </rewrite>
   </catalog>
  </models>
 </global>
</config>

I then proceeded to create Category.php at app\\code\\local\\ImpCat\\Catalog\\Model\\Convert\\Adapter\\Category.php

Category.php looks like this,

<?php
class ImpCat_Catalog_Model_Convert_Adapter_Category extends Mage_Eav_Model_Convert_Adapter_Entity
{
 protected $_categoryCache = array();
 protected $_stores;
 /**
 * Category display modes
 */
 protected $_displayModes = array( 'PRODUCTS', 'PAGE', 'PRODUCTS_AND_PAGE');

 public function parse()
 {
 $batchModel = Mage::getSingleton('dataflow/batch');
 $batchImportModel = $batchModel->getBatchImportModel();
 $importIds = $batchImportModel->getIdCollection();
 foreach ($importIds as $importId){
  $batchImportModel->load($importId);
  $importData = $batchImportModel->getBatchData();
  $this->saveRow($importData);
 }
 }
 /**
 * Save category (import)
 * @param array $importData
 * @throws Mage_Core_Exception
 * @return bool
 */
 public function saveRow(array $importData)
 {
 if (empty($importData['store'])) {
   if (!is_null($this->getBatchParams('store'))) {
   $store = $this->getStoreById($this->getBatchParams('store'));
   } else {
   $message = Mage::helper('catalog')->__('Skip import row, required field "%s" not defined', 'store');
   Mage::throwException($message);
   }
 }else{
  $store = $this->getStoreByCode($importData['store']);
 }
 if ($store === false){
  $message = Mage::helper('catalog')->__('Skip import row, store "%s" field not exists', $importData['store']);
  Mage::throwException($message);
 }
 $rootId = $store->getRootCategoryId();
  if (!$rootId) {
  return array();
  }
 $rootPath = '1/'.$rootId;
  if (empty($this->_categoryCache[$store->getId()])) {
  $collection = Mage::getModel('catalog/category')->getCollection()
              ->setStore($store)
              ->addAttributeToSelect('name');
 $collection->getSelect()->where("path like '".$rootPath."/%'");
 foreach ($collection as $cat) {
  $pathArr = explode('/', $cat->getPath());
  $namePath = '';
  for ($i=2, $l=sizeof($pathArr); $i<$l; $i++) {
  $name = $collection->getItemById($pathArr[$i])->getName();
  $namePath .= (empty($namePath) ? '' : '/').trim($name);
  }
  $cat->setNamePath($namePath);
 }
  $cache = array();
  foreach ($collection as $cat) {
  $cache[strtolower($cat->getNamePath())] = $cat;
  $cat->unsNamePath();
  }
  $this->_categoryCache[$store->getId()] = $cache;
  }
  $cache =& $this->_categoryCache[$store->getId()];
  $importData['categories'] = preg_replace('#\s*/\s*#', '/', trim($importData['categories']));
  if (!empty($cache[$importData['categories']])) {
  return true;
  }
  $path = $rootPath;
  $namePath = '';
  $i = 1;
 $categories = explode('/', $importData['categories']);
 /*$IsActive = $importData['IsActive'];*/
 $IsActive = $importData['is_active'];
 $IsAnchor =$importData['is_anchor'];
 $Description =$importData['description'];
 $IncludeInMenu=$importData['include_in_menu'];
 $MetaTitle=$importData['meta_title'];
 $MetaKeywords=$importData['meta_keywords'];
 $MetaDescription=$importData['meta_description'];
 $Image=$importData['image'];
 $URlkey=$importData['url_key'];
  foreach ($categories as $catName) {
  $namePath .= (empty($namePath) ? '' : '/').strtolower($catName);
  if (empty($cache[$namePath])) {
  $dispMode = $this->_displayModes[2];
    $cat = Mage::getModel('catalog/category')
    ->setStoreId($store->getId())
    ->setPath($path)
    ->setName($catName)
    ->setIsActive($IsActive)
    ->setIsAnchor($IsAnchor)
    ->setDisplayMode($dispMode)->save();
   $cat = Mage::getModel('catalog/category')->load($cat->getId());
   $cat->setIncludeInMenu($IncludeInMenu);
   $cat->setDescription($Description);
   $cat->setMetaTitle($MetaTitle).
    $cat->setMetaKeywords($MetaKeywords);
    $cat->setMetaDescription($MetaDescription);
    $cat->save();
   $cat = Mage::getModel('catalog/category')->load($cat->getId());
   $data['meta_keywords']=$MetaKeywords;
   $data['meta_title']=$MetaTitle;
   $data['meta_keywords']=$MetaKeywords;
   $data['meta_description']=$MetaDescription;
   $data['url_key']= $URlkey;
   $cat->addData($data);
   $cat->save();
  $cache[$namePath] = $cat;
  }
  $catId = $cache[$namePath]->getId();
  $path .= '/'.$catId;
  $i++;
  }
  return true;
 }

 /**
 * Retrieve store object by code
 *
 * @param string $store
 * @return Mage_Core_Model_Store
 */
 public function getStoreByCode($store)
 {
  $this->_initStores();
  if (isset($this->_stores[$store])) {
  return $this->_stores[$store];
  }
  return false;
 }

 /**
 * Init stores
 *
 * @param none
 * @return void
 */
 protected function _initStores ()
 {
  if (is_null($this->_stores)) {
  $this->_stores = Mage::app()->getStores(true, true);
  foreach ($this->_stores as $code => $store) {
  $this->_storesIdCode[$store->getId()] = $code;
  }
  }
 }
}

?>

I then continued to create ImpCat_All.xml at app\\etc\\modules ImpCat_All.xml looks like this,

<?xml version="1.0"?>
<config>
 <modules>
  <ImpCat_Catalog>
   <codePool>local</codePool>
   <active>true</active>
  </ImpCat_Catalog>
 </modules>
</config>

I then created a dataflow advanced profile at admin > system >Import/Export > Dataflow - Advanced Profile called category import, and added this XML code.

<action type="dataflow/convert_adapter_io" method="load">
     <var name="type">file</var>
     <var name="path">var/import</var>
     <var name="filename"><![CDATA[Categories.csv]]></var>
     <var name="format"><![CDATA[csv]]></var>
    </action>
    <action type="dataflow/convert_parser_csv" method="parse">
     <var name="delimiter"><![CDATA[,]]></var>
     <var name="enclose"><![CDATA["]]></var>
     <var name="fieldnames">true</var>
     <var name="store"><![CDATA[0]]></var>
     <var name="number_of_records">1</var>
     <var name="decimal_separator"><![CDATA[.]]></var>
     <var name="adapter">catalog/convert_adapter_category</var>
     <var name="method">parse</var>
 </action>

After many hours and days of trying one script after another, I finally figured out how to export and import all my categories to a new installation of Magento and keep all original ID's.

Exporting from your old Magento

Here's my export tool, exporter.php (run through browser or in CLI), put this file at your Magento root.

exporter.php

<?php
require_once 'app/Mage.php';
Mage::app();
$allCategories = Mage::getModel ( 'catalog/category' );
$categoryTree = $allCategories->getTreeModel();
$categoryTree->load();
$categoryIds = $categoryTree->getCollection()->getAllIds();
if ($categoryIds) {
  $outputFile = "var/export/categories-and-ids.csv";
  $write = fopen($outputFile, 'w');
  foreach ( $categoryIds as $categoryId ) {
    $parentId = $allCategories->load($categoryId)->getParentId();
    $data = array($parentId, $allCategories->load($categoryId)->getName(), $categoryId);
    fputcsv($write, $data);
  }
}
fclose($write);
echo "File written at /var/export";
?>

This produces a CSV-file at /var/export/categories-and-ids.csv Open this file and remove the top row containing your Default Category. You need to manually create a new Default Category in your installation, remember it's ID and correct your top level categories Parent ID. The CSV file you get from Export is structured as follows,

  1. First column is Parent_Id
  2. Second column is name of sub-category
  3. Third column is the original category ID from your old store

I recommend using OpenOffice Calc for editing and saving the CSV-file. The file MUST BE IN UTF-8 without BOM-format.

Importing to your new store

To import your categories from your created/edited CSV-file, you just run this importer from your Magento root. Remember to edit line 21 to reflect the name and location of your CSV.

create-categories.php

<?php
/**
* Script created by sonassi.com (http://www.sonassi.com/knowledge-base/quick-script-batch-create-magento-categories/)
*
* Edited by Christer Johansson for Magento 1.9.2.2 in december 2015
*
* File format of the CSV file categories-and-ids.csv :
* parent_category_id,category_name,category_id
* example: 3,subcat,5
* -> This will create a subcategory with 'subcat' as name and 5 as category id. The parent category id is 3 (Can also be Root
* Category with id 0).
*/

define('MAGENTO', realpath(dirname(__FILE__)));
require_once MAGENTO . '/app/Mage.php';

setlocale(LC_ALL, 'en_US.UTF-8');
umask(0);
Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID);

$file = fopen('./var/import/categories-and-ids.csv', 'r');
while (($column = fgetcsv($file)) !== FALSE) {
        //$column is an array of the csv elements
        if (!empty($column[0]) && !empty($column[1]) && !empty($column[2])) {
                $data['general']['name'] = $column[1];
                $data['general']['entity_id'] = $column[2];
                $data['general']['meta_title'] = "";
                $data['general']['meta_description'] = "";
                $data['general']['is_active'] = 1;
                $data['general']['url_key'] = "";
                $data['general']['display_mode'] = "PRODUCTS";
                $data['general']['is_anchor'] = 0;

                $data['category']['parent'] = $column[0]; // 2 or 3 is top level depending on Magento version
                $storeId = 0;

                createCategory($data, $storeId);
                sleep(0.5);
                unset($data);
        }
}

function createCategory($data, $storeId) {
        echo "Starting {$data['general']['name']} [{$data['category']['parent']}] ...";

        $category = Mage::getModel('catalog/category');
        $category->setStoreId($storeId);

        if (is_array($data)) {
                $category->addData($data['general']);

                $parentId = $data['category']['parent'];
                $parentCategory = Mage::getModel('catalog/category')->load($parentId);
                $category->setPath($parentCategory->getPath() . "/" . $category->getId());

                /**
                * Check "Use Default Value" checkboxes values
                */
                if ($useDefaults = $data['use_default']) {
                        foreach ($useDefaults as $attributeCode) {
                                $category->setData($attributeCode, null);
                        }
                }

                $category->setAttributeSetId($category->getDefaultAttributeSetId());

                if (isset($data['category_products']) && !$category->getProductsReadonly()) {
                        $products = [];
                        parse_str($data['category_products'], $products);
                        $category->setPostedProducts($products);
                }

                try {
                        $category->save();
                        echo "Import successful - ID: " . $category->getId() . " - " . $category->getPath() . "<br /> ";
                } catch (Exception $e){
                        echo "Failed import <br />";
                }
        }

}

Depending on how big your site is and how many categories you are importing, this will take anything from a few seconds to minutes or even hours if you have thousands of them.

Just be patient, and the script will give you a list of all imported categories and show you if any failed to import. Remember to clean your category names before import.

After import is done, clear your cache and re-index Magento through Admin. Check out your categories in your Manage Categories, and start importing or creating products.

Good luck! :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM