ZenCart data import - admin/custom menu.php
computing: software: ZenCart: importing data: $zc/admin/custom_menu.php
Overview
This file does the actual import. It contains a number of classes which might later be split off into separate PHP files, as they model particular aspects of the ZenCart data.
Source
<php><?php // // +----------------------------------------------------------------------+ // |zen-cart Open Source E-commerce | // +----------------------------------------------------------------------+ // | Copyright (c) 2003 The zen-cart developers | // | | // | http://www.zen-cart.com/index.php | // | | // | Portions Copyright (c) 2003 osCommerce | // +----------------------------------------------------------------------+ // | This source file is subject to version 2.0 of the GPL license, | // | that is bundled with this package in the file LICENSE, and is | // | available through the world-wide-web at the following url: | // | http://www.zen-cart.com/license/2_0.txt. | // | If you did not receive a copy of the zen-cart license and are unable | // | to obtain it through the world-wide-web, please send a note to | // | license@zen-cart.com so we can mail you a copy immediately. | // +----------------------------------------------------------------------+ // /*
2006-09-17 (wzl) handlers for "Custom" menu. Used modules.php as model.
SET values:
prod_entry (default): bulk product entry ACTION values: (none): show bulk product entry form check: data is being submitted for preview commit: data is being submitted for final commit (update database)
- /
require('includes/application_top.php');
define('CUSTOM_MODULE_SET_PROD_ENTRY','prod_entry');
define('CUSTOM_MODULE_SAVE_DATA','save');
define('CUSTOM_MODULE_PROD_DATA_NAME','products');
define('CUSTOM_MODULE_ACT_CHECK','check');
define('CUSTOM_MODULE_ACT_COMMIT','commit');
define('CUSTOM_MODULE_BTN_CHECK','Preview Changes');
define('CUSTOM_MODULE_BTN_COMMIT','COMMIT');
define('URL_ISBN_SEARCH','http://www.abebooks.com/servlet/SearchResults?isbn=<<1>>');
define('CUSTOM_DEFAULT_SUPPLIER','Jubilee'); // when import data supplier field is empty
define('CUSTOM_DEFAULT_CATEGORY','Unfiled'); // when imported category field is empty
define('TABLE_CUSTOM_IMPORT_PROD',DB_PREFIX.'custom_import_prod');
define('TABLE_CUSTOM_IMPORT_MFGRS',DB_PREFIX.'custom_import_mfgrs');
// new item
define('HTML_STATUS_NEW', 'NEW');
// item is saved in list
define('HTML_STATUS_NOTED', 'ok');
// item found in database
define('HTML_STATUS_EXISTS', 'found');
$set = (isset($_GET['set']) ? $_GET['set'] : );
$button = (isset($_POST['action']) ? $_POST['action'] : );
switch ($button) {
case CUSTOM_MODULE_BTN_CHECK: $action=CUSTOM_MODULE_ACT_CHECK; break;
case CUSTOM_MODULE_BTN_COMMIT: $action=CUSTOM_MODULE_ACT_COMMIT; break;
default: $action=;
}
/*
After page has displayed, this handles the user's input
- /
switch ($action) {
case CUSTOM_MODULE_SAVE_DATA:
$doSave = true;
// new SQL code for updating products: $sqlUpdateProd = "update " . TABLE_PRODUCTS . " set configuration_value = '" . $value . "' where configuration_key = '" . $key ."'";
break; case 'enter': // showing data entry form, so this stage (data processing) does nothing default: }
?> <!doctype html public "-//W3C//DTD HTML 4.01 Transitional//EN"> >
Previewing entered data:"; ProcessData(false); break; case CUSTOM_MODULE_ACT_COMMIT: echo "Saving entered data:"; $hide_form = 1; ProcessData(true); break; default: } /* DEFAULT: show bulk product entry form check: data is being submitted for preview commit: data is being submitted for final commit (update database) */ // always show data entry form: } if (!$hide_form) { $htmlSep = '<tab>'; echo zen_draw_form('prod_entry', CUSTOM_MENU_MODULE); echo '
| ';
echo 'Enter product data here: '; echo 'Format is: ' .'ID string'.$htmlSep .'(ignored)'.$htmlSep .'Title'.$htmlSep .'(ignored)'.$htmlSep .'Supplier'.$htmlSep .'Price '; echo ' | |
| '; echo ''; echo ''; echo ' | '; echo ''; echo ' |
';
echo '';
}
?>
<?php
require(DIR_WS_INCLUDES . 'application_bottom.php');
function Pluralize($iQty, $iSing=, $iPlur='s') {
if ($iQty == 1) {
return $iSing;
} else {
return $iPlur;
}
}
function ProcessData($iCommit) {
$data_raw = $_POST[CUSTOM_MODULE_PROD_DATA_NAME];
$data_lines = explode("\n",$data_raw);
echo '
'; echo ''; echo '';$ctrTitlesNew = 0; $ctrTitlesOld = 0;
foreach ($data_lines as $data_line) {
// create title object for each import line. Title object should do all the lookups and printing and stuff.
if ($data_line) {
$objTitle = clsTitles::Import($data_line);
$ctrSuppFnd = clsSuppliers::Count(); // # of suppliers found
$ctrSuppNew = clsSuppliers::CountNew(); // # of *new* suppliers
$ctrCatgFnd = clsCategories::Count(); // # of new categories
$ctrCatgNew = clsCategories::CountNew(); // # of new categories
echo ''.$objTitle->TableRowCells().'';
}
}
if ($ctrSuppNew) {
$htmlSuppList = ': '.clsSuppliers::DoListNew('','',', ');
$htmlSuppList .= ' OLD: '.clsSuppliers::DoListOld('','',', ');
}
if ($ctrCatgNew) {
$htmlCatgList = ': '.clsCategories::DoListNew('','',', ');
$htmlCatgList .= ' OLD: '.clsCategories::DoListOld('','',', ');
}
echo '| Data Entry Status | |||||||
|---|---|---|---|---|---|---|---|
| Catg | ID | Title | Supplier | Price | Supplier | Title | Category |
'; echo 'Processed '.$ctrLines.' lines:
- '
.'
- '.clsTitles::Records()->CountNew().' new titles to add' .'
- '.clsTitles::Records()->CountOld().' titles to update (ignored for now)' .'
- '.$ctrSuppFnd.' supplier'.Pluralize($ctrSuppFnd).' in import, '.$ctrSuppNew.' new'.$htmlSuppList .'
- '.$ctrCatgFnd.' categor'.Pluralize($ctrCatgFnd,'y','ies').' in import, '.$ctrCatgNew.' new'.$htmlCatgList .'
';
echo 'Adding suppliers: '.clsSuppliers::Save($iCommit).'
'; echo 'Adding categories: '.clsCategories::Save($iCommit).'
'; echo 'Adding titles: '.clsTitles::Save($iCommit).'
';
} function MakeKey($iStr) {
return preg_replace('/[ -\.,;]*/',,strtolower($iStr));
} /*
===== CLASSES =====
- /
class clsRecords {
public $List; // actual unique records public $qtyNew; // number of *new* records found during import public $qtyOld;
public function Count() {
return Count($this->List);
}
public function CountOld() {
if ($this->qtyOld) {
return $this->qtyOld;
} else {
return 0;
}
}
public function CountNew() {
if ($this->qtyNew) {
return $this->qtyNew;
} else {
return 0;
}
}
public function AddObject($iName,$iObj) {
if (!$this->List[$iName]) {
$this->List[$iName] = $iObj;
}
if ($iObj->isFound) {
$this->qtyOld++;
} else {
$this->qtyNew++;
}
}
public function Exists($iName) {
if (is_array($this->List)) {
$isSet = isset($this->List[$iName]);
return $isSet;
} else {
return false;
}
}
public function DoListNew($iPfx,$iSfx,$iSep) {
foreach ($this->List as $obj) {
if (!$obj->isFound) {
if ($out) {
$out .= $iSep;
}
$out .= $iPfx.$obj->Name.$iSfx;
}
}
return $out;
}
public function DoListOld($iPfx,$iSfx,$iSep) {
foreach ($this->List as $obj) {
if ($obj->isFound) {
if ($out) {
$out .= $iSep;
}
$out .= $iPfx.$obj->Name.$iSfx;
}
}
return $out;
}
}
class clsTitles {
private static $objRecords;
public function Records() {
self::InitRecords();
return self::$objRecords;
}
public function Import($iLine) {
$obj = new clsTitle;
$obj->ImportLine($iLine);
if (!$obj->isCatg) {
self::Records()->AddObject($obj->ImportKey,$obj);
}
return $obj;
}
public function Save($iCommit) {
global $db;
$result = '
- ';
foreach (self::Records()->List as $obj) {
$result .= $obj->Save($iCommit);
}
$result .= '
';
return $result;
}
public function Count() {
return self::Records()->Count();
}
public function CountNew() {
return self::Records()->CountNew();
}
public function DoListNew($iPfx,$iSfx,$iSep) {
return self::Records()->DoListNew($iPfx,$iSfx,$iSep);
}
protected function InitRecords() {
if (!isset(self::$objRecords)) {
self::$objRecords = new clsRecords;
}
}
}
class clsTitle {
public $ImportKey; private $intID; public $Name; public $Price; public $Supplier; public $SuppImp; public $Category; public $CatgImp; public $isCatg;
// calculated fields
public $ISBN; public $ISBN_URL; public $HtmlName;
// status fields
public $Status; public $isFound;
// public static $lstTitles;
public function ID() {
if (!isset($this->intID)) {
$this->UpdateName();
}
//echo 'TITLE ID='.$this->intID;
return $this->intID; }
public function ImportLine($iLine) {
global $db;
list($ImportKeyRaw,$notUsed,$this->Name,$notUsed,$strSupplierName,$notUsed,$this->Price) = explode("\t",$iLine);
//echo 'NAME='.$Name.'
';
// Check to see if the title is actually a category record - price is 0, name is empty or contains "classification"
$this->isCatg = false;
if ($this->Price == 0.0) {
if ((!MakeKey($this->Name)) || (eregi('classification',$this->Name))) {
$this->isCatg = true;
}
}
if ($this->isCatg) {
// for now, we're not really doing anything with category lines
$this->HtmlName = ''.$this->Name.'';
} else {
// ** Supplier
if ($strSupplierName == ) {
$strSupplierName = CUSTOM_DEFAULT_SUPPLIER;
}
$this->SuppImp = clsSuppliers::Import($strSupplierName);
$this->Supplier = $this->SuppImp->Supplier;
// Parse out the category and title key
$listTitleParts = array_reverse(split(':',$ImportKeyRaw));
$this->ImportKey = MakeKey(array_shift($listTitleParts));
$strCatg = array_shift($listTitleParts); // for now, assume just one level of category
if (!$strCatg) {
$strCatg = CUSTOM_DEFAULT_CATEGORY;
}
$this->CatgImp = clsCategoryImports::Import($strCatg);
$this->Category = $this->CatgImp->Category;
//echo 'CATG='.$strCatg.' stored='.$this->Category->Name.'
';
$this->UpdateName();
// ** Title: cross-reference import key to title ID
$sqlFind = 'SELECT * FROM '.TABLE_CUSTOM_IMPORT_PROD.' WHERE import_key="'.$this->ImportKey.'";';
$qryTitle = $db->Execute($sqlFind);
if ($qryTitle->RecordCount()) {
$this->isFound = true;
$this->Status = HTML_STATUS_EXISTS;
$this->ID = $qryTitle->fields['prod_key'];
} else {
$this->isFound = false;
if ($lstTitles[$this->ImportKey]) { $this->Status = HTML_STATUS_NOTED;
} else {
$this->Status = HTML_STATUS_NEW;
// $lstTitles[$this->ImportKey] = $this->ID; // may eventually want to save an object, not just a string
}
}
}
}
public function UpdateName() {
$subject = $this->Name;
$pattern = '/ISBN *[0-9\-]*/';
preg_match($pattern, $subject, $matches, PREG_OFFSET_CAPTURE);
// This operation is unnecessarily complicated, but it is what seems to work:
$this->ISBN = trim(preg_replace('/ISBN/',,$matches[0][0]));
if ($this->ISBN) {
$this->ISBN_URL = preg_replace('/<<1>>/',$this->ISBN,URL_ISBN_SEARCH);
$this->HtmlName = '<a href="'.$this->ISBN_URL.'">'.$this->Name.'</a>';
} else {
$this->HtmlName = $this->Name;
$this->ISBN_URL = ;
}
}
public function Save($iCommit) {
global $db;
if ($this->isFound) {
// TO DO: write update routine
} else {
// Check for missing manufacturer:
if (!$this->Supplier->ID()) {
echo 'MISSING SUPPLIER for title "'.$this->Name.'"
';
}
if (!$this->Category->ID()) {
echo 'MISSING CATEGORY for title "'.$this->Name.'"
';
}
// only insert items with a numerically valid price
if (is_numeric(trim($this->Price))) {
// Theory: MySQL defaults to using the first index as an auto-increment key. We'll see if this works. // Update main PRODUCTS table:
$sqlAdd = 'INSERT INTO '.TABLE_PRODUCTS.' (products_status,products_price,products_date_added,manufacturers_id,master_categories_id)'
.'VALUES(' .'1,' // products_status (1 = active) .$this->Price.',' // products_price .'NOW(),' // products_date_added .$this->Supplier->ID().',' // manufacturers_id .$this->Category->ID().')'; // master_categories_id
$result .= '
if ($this->isCatg) {
$out .= 'category (ignored)';
} else {
$out .= '('.$this->Supplier->ID().') '.$this->Supplier->Name.''.$this->Price.''.$this->SuppImp->Status.''.$this->Status.''.$this->CatgImp->Status.'';
} return $out; }
}
class clsSuppliers {
private static $Records;
public function Import($iName) {
self::InitRecords();
$objSuppImp = new clsSupplierImport;
if (self::$Records->List[$iName]) {
// supplier has already been seen this session
$objSupp = self::$Records->List[$iName]; // retrieve existing supplier record
$objSuppImp->ImportOld($objSupp); // attach it to supplier import record for this import
} else {
// new supplier for this session
$objSuppImp->ImportNew($iName);
self::$Records->AddObject($iName,$objSuppImp->Supplier);
// self::$Records->List[$iName] = $objSuppImp->Supplier;
// if (!$objSuppImp->Supplier->isFound) {
// $this->Records->qtyNew++;
// }
}
return $objSuppImp;
}
// save list of (new) suppliers to database
public function Save($iCommit) {
global $db;
$result = '- ';
foreach (self::$Records->List as $obj) {
if (!$obj->isFound) {
if ($strValues) {
$strValues .= ',';
}
$strValues .= '("'.mysql_real_escape_string($obj->Name).'",NOW())';
}
}
if ($strValues) {
$sqlAdd = 'INSERT INTO '.TABLE_MANUFACTURERS.' (manufacturers_name, date_added) VALUES'.$strValues;
$result .= '
- SQL: '.$sqlAdd; if ($iCommit) { $db->Execute($sqlAdd); $result .= '
- status: '.mysql_info(); } } $result .= '
return $result;
}
public function Count() {
self::InitRecords();
return self::$Records->Count();
}
public function CountNew() {
self::InitRecords();
return self::$Records->CountNew();
}
public function DoListNew($iPfx,$iSfx,$iSep) {
self::InitRecords();
return self::$Records->DoListNew($iPfx,$iSfx,$iSep);
}
public function DoListOld($iPfx,$iSfx,$iSep) {
self::InitRecords();
return self::$Records->DoListOld($iPfx,$iSfx,$iSep);
}
protected function InitRecords() {
if (!isset(self::$Records)) {
self::$Records = new clsRecords;
}
}
}
class clsSupplier {
private $intID; public $Name; public $Key; public $isFound;
public function Init($iName) {
global $db;
$this->Name = $iName;
$this->UpdateName();
}
public function Init_fromID($iID) {
global $db;
$this->intID = $iID;
$sqlFind = 'SELECT * FROM '.TABLE_MANUFACTURERS.' WHERE manufacturers_id="'.$iID.'";';
$qryFind = $db->Execute($sqlFind);
$this->isFound = $qryFind->RecordCount();
if ($this->isFound) {
$this->Name = $qryFind->fields['manufacturers_name'];
}
}
private function UpdateName() {
global $db;
$sqlFind = 'SELECT * FROM '.TABLE_MANUFACTURERS.' WHERE manufacturers_name="'.$this->Name.'";';
$qryFind = $db->Execute($sqlFind);
$this->isFound = $qryFind->RecordCount();
if ($this->isFound) {
$this->intID = $qryFind->fields['manufacturers_id'];
} else {
// not found in main list, so check aliases
$sqlFind = 'SELECT * FROM '.TABLE_CUSTOM_IMPORT_MFGRS.' WHERE LCASE(import_alias)="'.mysql_real_escape_string(strtolower($this->Name)).'";';
$qryFind = $db->Execute($sqlFind);
$this->isFound = $qryFind->RecordCount();
if ($this->isFound) {
$this->Init_fromID($qryFind->fields['id_mfgr']);
}
}
}
public function ID() {
if ($this->intID) {
$this->UpdateName();
}
return $this->intID;
}
}
class clsSupplierImport {
public $Supplier; // points to supplier data public $Status; // indicates status of this particular import of that data
// Supplier record has already been created, so use it:
public function ImportOld($iObj) {
$this->Supplier = $iObj;
$this->Status = HTML_STATUS_NOTED;
}
// Supplier record needs to be created:
public function ImportNew($iName) {
global $db;
$this->Supplier = new clsSupplier;
$this->Supplier->Init($iName);
if ($this->Supplier->isFound) {
$this->Status = HTML_STATUS_EXISTS;
} else {
$this->Status = HTML_STATUS_NEW;
}
}
}
/*
===== CATEGORIES =====
- /
class clsCategories {
private static $Records;
public function Create($iName) {
// This function is only called if category has not been seen before in this run
global $db;
$objNew = new clsCategory; self::InitRecords(); $objNew->Init($iName); self::$Records->AddObject($iName,$objNew);
/* self::$Records->List[$iName] = $objNew;
if (!$objNew->isFound) {
self::$Records->qtyNew++;
}
- /
return $objNew; }
// add any new categories to database
public function Save($iCommit) {
foreach (self::$Records->List as $obj) {
if (!$obj->isFound) {
$sqlOut .= $obj->Save($iCommit);
}
}
return $sqlOut;
}
public function GetObject($ID) {
self::InitRecords();
return self::$Records->List[$ID];
}
public function Count() {
self::InitRecords();
return self::$Records->Count();
}
public function CountNew() {
self::InitRecords();
return self::$Records->CountNew();
}
public function Exists($iName) {
self::InitRecords();
return self::$Records->Exists($iName);
}
public function DoListNew($iPfx,$iSfx,$iSep) {
self::InitRecords();
return self::$Records->DoListNew($iPfx,$iSfx,$iSep);
}
public function DoListOld($iPfx,$iSfx,$iSep) {
self::InitRecords();
return self::$Records->DoListOld($iPfx,$iSfx,$iSep);
}
protected function InitRecords() {
if (!isset(self::$Records)) {
self::$Records = new clsRecords;
}
}
} class clsCategory {
private $intID; public $Name; public $ImportKey;
// status
public $isFound;
public function Init($iName) {
global $db;
//echo 'storing 2:'.$iName.' ';
$this->Name = $iName;
$this->ImportKey = MakeKey($iName);
$this->UpdateName();
}
private function UpdateName() {
global $db;
$sqlFind = 'SELECT * FROM '.TABLE_CATEGORIES_DESCRIPTION.' WHERE categories_name="'.$this->Name.'"';
$qryFind = $db->Execute($sqlFind);
$this->isFound = $qryFind->RecordCount();
$this->intID = $qryFind->fields['categories_id'];
}
public function ID() {
if (!$this->intID) {
$this->UpdateName();
}
return $this->intID;
}
public function Save($iCommit) {
global $db;
$result = '- ';
$sqlAdd = 'INSERT INTO '.TABLE_CATEGORIES.' (date_added) VALUES(NOW())';
$result .= '
- SQL: '.$sqlAdd; if ($iCommit) { $db->Execute($sqlAdd); $result .= '
- status: '.mysql_info(); $idNew = mysql_insert_id(); $result .= '
- ID: '.$idNew; } else { $idNew = '?'; } $sqlAdd = 'INSERT INTO '.TABLE_CATEGORIES_DESCRIPTION.' (categories_id,categories_name) VALUES(' .$idNew.',"'.mysql_real_escape_string($this->Name).'");'; $result .= '
- SQL: '.$sqlAdd; if ($iCommit) { $db->Execute($sqlAdd); $result .= '
- status: '.mysql_info(); } $result .= '
return $result; }
}
class clsCategoryImports {
public function Import($iName) {
$objImport = new clsCategoryImport;
$objImport->Import($iName);
return $objImport;
}
}
class clsCategoryImport {
public $Category; public $Status;
public function Import($iName) {
// echo 'storing 1:'.$iName.' ';
if (clsCategories::Exists($iName)) {
//echo 'EXISTS ';
$this->Category = clsCategories::GetObject($iName);
$this->Status = HTML_STATUS_NOTED;
} else {
//echo '*NEW* ';
$this->Category = clsCategories::Create($iName);
if ($this->Category->isFound) {
$this->Status = HTML_STATUS_EXISTS;
} else {
$this->Status = HTML_STATUS_NEW;
}
}
}
}
?></php>