private function _ImportImage($productId, $record, $index = '') { $existingImage = false; $imageId = 0; if (!empty($record['prodimageid' . $index]) && IsId($record['prodimageid' . $index])) { $imageId = $record['prodimageid' . $index]; try { $existingImage = new ISC_PRODUCT_IMAGE((int)$imageId); if ($existingImage->getProductId() != $productId) { // the existing image doesn't belong to this product $existingImage = false; } } catch (Exception $ex) { } } $imageFile = $record['prodimagefile' . $index]; $imageDescription = ''; if (!empty($record['prodimagedescription' . $index])) { $imageDescription = $record['prodimagedescription' . $index]; } $imageIsThumb = false; if (!empty($record['prodimageisthumb' . $index])) { $imageIsThumb = $record['prodimageisthumb' . $index]; } $imageSort = -1; if (isset($record['prodimagesort' . $index]) && $record['prodimagesort' . $index] != '') { $imageSort = (int)$record['prodimagesort' . $index]; } $importedImage = false; if (!$existingImage || $existingImage->getSourceFilePath() != $imageFile) { if (preg_match('#^(?P<scheme>[a-zA-Z0-9\.]+)://#i', $imageFile, $matches)) { // code exists in the new product image management classes to handle these imports $imageAdmin = new ISC_ADMIN_PRODUCT_IMAGE(); // the filename is an external URL, import it against the calcualted product hash $imageAdmin->importImagesFromUrls(false, array($imageFile), $importImages, $importImageErrors, false, true); if (!empty($importImages)) { $importedImage = $importImages[0]; } if (!empty($importImageErrors)) { // as this import works on one file only and importImagesFromWebUrls creates one error per file, can simply tack on the new error $importImageError = $importImageErrors[0]; if (is_array($importImageError)) { $this->ImportSession['Results']['Warnings'][] = $importImageError[1]; } else { $this->ImportSession['Results']['Warnings'][] = $importImageError; } } } else { // the filename is a local file $importImageFilePath = ISC_BASE_PATH . "/" . GetConfig('ImageDirectory') . "/import/" . $imageFile; if (file_exists($importImageFilePath)) { try { $importedImage = ISC_PRODUCT_IMAGE::importImage($importImageFilePath, basename($importImageFilePath), false, false, false, false); $productImages[] = $importedImage; } catch (Exception $exception) { $this->ImportSession['Results']['Warnings'][] = $exception->getMessage(); } } else { $this->ImportSession['Results']['Warnings'][] = $record['prodname'].GetLang('ImportProductImageDoesntExist'); } } } // do we have an existing image? if ($existingImage) { // assign the imported image file to our existing image if ($importedImage) { $existingImage->setSourceFilePath($importedImage->getSourceFilePath()); $existingImage->saveToDatabase(false); } // use the existing image to set the description, thumb, sort $importedImage = $existingImage; } if ($importedImage) { $importedImage->setDescription($imageDescription); $importedImage->setIsThumbnail($imageIsThumb); if ($imageSort >= 0) { $importedImage->setSort($imageSort); } } return $importedImage; }
/** * _GetVariationData * Load the variation data for a product either from the form or database * * @param Int $ProductId The ID of the product to load variations for. 0 if it's a new product * @param String $RefArray The array to store the variation details in * @return Void */ public function _GetVariationData($ProductId = 0, &$RefArray = array()) { if($ProductId == 0) { // First, do we even have a variation selected? if(isset($_POST['variationId']) && is_numeric($_POST['variationId']) && isset($_POST['options'])) { foreach($_POST['options'] as $option_counter => $option) { $tmp = array(); // The combination ID hasn't been assigned yet if(isset($option['id'])) { $tmp['combinationid'] = $option['id']; } else { $tmp['combinationid'] = 0; } // The product ID hasn't been assigned yet $tmp['vcproductid'] = 0; // The variation id $tmp['vcvariationid'] = (int)$_POST['variationId']; // Is the combination enabled? $tmp['vcenabled'] = 0; if(isset($option['enabled'])) { $tmp['vcenabled'] = 1; } // The variation option combination $ids = preg_replace("/^#/", "", $option['variationcombination']); $ids = str_replace("#", ",", $ids); $tmp['vcoptionids'] = $ids; // The product option's SKU $tmp['vcsku'] = $option['sku']; // The price difference type $tmp['vcpricediff'] = $option['pricediff']; // The price difference or fixed price $tmp['vcprice'] = DefaultPriceFormat($option['price']); // The weight difference type $tmp['vcweightdiff'] = $option['weightdiff']; // The weight difference or fixed weight $tmp['vcweight'] = DefaultDimensionFormat($option['weight']); $tmp['vcimage'] = ''; $tmp['vcimagezoom'] = ''; $tmp['vcimagestd'] = ''; $tmp['vcimagethumb'] = ''; if (isset($_FILES['options']['name'][$option_counter]['image']) && $_FILES['options']['name'][$option_counter]['image'] != '') { try { $image = ISC_PRODUCT_IMAGE::importImage( $_FILES['options']['tmp_name'][$option_counter]['image'], $_FILES['options']['name'][$option_counter]['image'], false, false, true, false ); $tmp['vcimage'] = $image->getSourceFilePath(); $tmp['vcimagezoom'] = $image->getResizedFilePath(ISC_PRODUCT_IMAGE_SIZE_ZOOM, true, false); $tmp['vcimagestd'] = $image->getResizedFilePath(ISC_PRODUCT_IMAGE_SIZE_STANDARD, true, false); $tmp['vcimagethumb'] = $image->getResizedFilePath(ISC_PRODUCT_IMAGE_SIZE_THUMBNAIL, true, false); } catch (Exception $ex) { } } elseif (isset($option['delimage'])) { $tmp['vcimage'] = "REMOVE"; } // The current stock level if(isset($option['currentstock'])) { $tmp['vcstock'] = (int)$option['currentstock']; } else { $tmp['vcstock'] = 0; } // The low stock level if(isset($option['lowstock'])) { $tmp['vclowstock'] = (int)$option['lowstock']; } else { $tmp['vclowstock'] = 0; } // Push the option to the stack array_push($RefArray, $tmp); } } } }
/** * Processor for importing an image via external URL * * @param int|string $productId Id of a product to import images to, or hash of a product being created if $hash is true * @param array $urls A list of image urls to import * @param array $images By reference blank array to be populated with successful images * @param array $errors By reference blank array to be populated with errors - each element may be a string or an array(url, error) * @param bool $hash If true, $productId will be treated as a product hash * @param bool $generateImages If true, when importing, will attempt to generate thumbnail images -- may not be desirable if importing many images at once */ public function importImagesFromUrls($productId, $urls, &$images, &$errors, $hash = false, $generateImages = true) { foreach ($urls as $originalUrl) { $url = $originalUrl; if (!preg_match('#^[a-zA-Z0-9\.]+://#i', $url)) { // no scheme provided in the url, assume http $url = 'http://' . $url; } $urlInfo = @parse_url($url); if (!$urlInfo) { $errors[] = array($originalUrl, sprintf(GetLang('ProductImageInvalidUrl'), $originalUrl)); continue; } if ($urlInfo['scheme'] != 'http' && $urlInfo['scheme'] != 'https') { $errors[] = array($originalUrl, sprintf(GetLang('ProductImageHttpOnly'), $originalUrl)); continue; } $response = PostToRemoteFileAndGetResponse($url, '', 90, $ptrfError); if (!$response) { // show error with details from PostToRemoteFileAndGetResponse switch ($ptrfError) { case ISC_REMOTEFILE_ERROR_TIMEOUT: $error = GetLang('ProductImageCouldNotBeDownloadedTimeout'); break; case ISC_REMOTEFILE_ERROR_HTTPERROR: $error = GetLang('ProductImageCouldNotBeDownloadedHttpError'); break; case ISC_REMOTEFILE_ERROR_EMPTY: $error = GetLang('ProductImageCouldNotBeDownloadedEmpty'); break; case ISC_REMOTEFILE_ERROR_DNSFAIL: $error = GetLang('ProductImageCouldNotBeDownloadedDns'); break; default: $error = sprintf(GetLang('ProductImageCouldNotBeDownloadedOther'), $ptrfError); break; } $errors[] = array($originalUrl, $error); continue; } // to work correctly with the product image 'import' process the image must be a file, so save it to the cache directory temporarily while (true) { // we can name it .tmp because the extension will be corrected after the image type is detected $temporaryPath = ISC_CACHE_DIRECTORY . 'productimage_' . ISC_PRODUCT_IMAGE::randomString(16) . '.tmp'; if (!file_exists($temporaryPath)) { break; } } $fh = @fopen($temporaryPath, 'wb'); if (!$fh) { $errors[] = array($originalUrl, GetLang('ProductImageCacheWriteError')); continue; } if (!@fwrite($fh, $response)) { $errors[] = array($originalUrl, GetLang('ProductImageCacheWriteError')); @fclose($fh); continue; } @fclose($fh); // determine original filename based on request path $originalFilename = @$urlInfo['path']; if ($originalFilename) { $pathInfo = pathinfo($urlInfo['path']); } if ($originalFilename && $pathInfo['basename']) { $originalFilename = $pathInfo['basename']; } else { // if no original filename was specified (e.g.: the image was the result of a script like http://www.example.com/) then generate a random name for it // don't need an extension because importImage will add the correct one for the type of image it is $originalFilename = 'image' . ISC_PRODUCT_IMAGE::randomString(3); } try { $image = ISC_PRODUCT_IMAGE::importImage($temporaryPath, $originalFilename, $productId, $hash, true, $generateImages); } catch (ISC_PRODUCT_IMAGE_IMPORT_INVALIDIMAGEFILE_EXCEPTION $exception) { $errors[] = array($originalUrl, $exception->getMessage() . ' ' . GetLang('ProductImageInvalidFileFromWeb')); @unlink($temporaryPath); continue; } catch (ISC_PRODUCT_IMAGE_IMPORT_EXCEPTION $exception) { // these exceptions should have language-powered messages so are safe to return to the user $errors[] = array($originalUrl, $exception->getMessage()); @unlink($temporaryPath); continue; } catch (Exception $exception) { // other unknown error $errors[] = array($originalUrl, GetLang('ProductImageProcessUnknownError')); @unlink($temporaryPath); continue; } // all done, add to list of successful images $images[] = $image; } }
private function BulkUpdateVariations() { $productId = 0; $vid = 0; $inv = 0; $useHash = false; if(isset($_GET['v']) && is_numeric($_GET['v']) && isset($_GET['inv']) && is_numeric($_GET['inv'])) { $vid = (int)$_GET['v']; $inv = (bool)$_GET['inv']; } if (isset($_GET['productId'])) { $productId = (int)$_GET['productId']; } if (isId($productId)) { $query = 'SELECT prodvariationid FROM [|PREFIX|]products WHERE productid = ' . $productId; $res = $GLOBALS['ISC_CLASS_DB']->Query($query); if ($row = $GLOBALS['ISC_CLASS_DB']->Fetch($res)) { if ($row['prodvariationid'] != $vid) { $useHash = true; } } } if (!empty($_GET['productHash'])) { $useHash = true; $productId = $GLOBALS['ISC_CLASS_DB']->Quote($_GET['productHash']); } if ($useHash) { $whereSQL = "vcproductid = 0 AND vcproducthash = '" . $productId . "' "; } else { $whereSQL = 'vcproductid = ' . $productId . ' '; } $filterOptions = array(); if (isset($_GET['filterOptions'])) { parse_str($_GET['filterOptions'], $filterOptions); } // create the sql to update the filtered options $optionSQL = ''; if (!empty($filterOptions)) { foreach ($filterOptions as $optionName => $optionValues) { $thisOptionSQL = ''; foreach ($optionValues as $value) { if ($value == 'all') { continue; } if ($thisOptionSQL) { $thisOptionSQL .= ' OR '; } $thisOptionSQL .= "CONCAT(',', vcoptionids, ',') LIKE '%," . $value . ",%'"; } if ($thisOptionSQL) { if ($optionSQL) { $optionSQL .= " AND "; } $optionSQL .= "(" . $thisOptionSQL . ")"; } } } if ($optionSQL != '') { $optionSQL = ' AND ' . $optionSQL; } $updates = array(); switch ($_GET['updatePurchaseable']) { case "reset": case "yes": $updates[] = "vcenabled = '1'"; break; case "no": $updates[] = "vcenabled = '0'"; break; } switch ($_GET['updatePriceDiff']) { case "reset": $updates[] = "vcpricediff = ''"; $updates[] = "vcprice = 0"; break; case "add": case "subtract": case "fixed": $updates[] = "vcpricediff = '" . $_GET['updatePriceDiff'] . "'"; $updates[] = "vcprice = " . (float)$_GET['updatePrice']; break; } switch ($_GET['updateWeightDiff']) { case "reset": $updates[] = "vcweightdiff = ''"; $updates[] = "vcweight = 0"; break; case "add": case "subtract": case "fixed": $updates[] = "vcweightdiff = '" . $_GET['updateWeightDiff'] . "'"; $updates[] = "vcweight = " . (float)$_GET['updateWeight']; break; } if ($inv) { if ($_GET['updateStockLevel'] != '') { $updates[] = 'vcstock = ' . (int)$_GET['updateStockLevel']; } if ($_GET['updateLowStockLevel'] != '') { $updates[] = 'vclowstock = ' . (int)$_GET['updateLowStockLevel']; } } // delete existing images? if (isset($_GET['updateDelImages'])) { // get distinct images not associated with variations that aren't in the current filter $query = ' SELECT vcimagezoom, vcimagestd, vcimagethumb FROM [|PREFIX|]product_variation_combinations pvc WHERE ' . $whereSQL . $optionSQL . ' GROUP BY vcimagezoom HAVING COUNT(*) = ( SELECT COUNT(*) FROM [|PREFIX|]product_variation_combinations pvc2 WHERE pvc2.vcproductid = pvc.vcproductid AND pvc2.vcimagezoom = pvc.vcimagezoom ) '; $res = $GLOBALS['ISC_CLASS_DB']->Query($query); while ($row = $GLOBALS['ISC_CLASS_DB']->Fetch($res)) { GetClass('ISC_ADMIN_PRODUCT')->DeleteVariationImagesForRow($row); } $updates[] = "vcimage = ''"; $updates[] = "vcimagezoom = ''"; $updates[] = "vcimagestd = ''"; $updates[] = "vcimagethumb = ''"; } // import image elseif (isset($_FILES['updateImage'])) { try { $image = ISC_PRODUCT_IMAGE::importImage($_FILES['updateImage']['tmp_name'], $_FILES['updateImage']['name'], false, false, true, false); $zoom = $image->getResizedFilePath(ISC_PRODUCT_IMAGE_SIZE_ZOOM, true, false); $standard = $image->getResizedFilePath(ISC_PRODUCT_IMAGE_SIZE_STANDARD, true, false); $thumb = $image->getResizedFilePath(ISC_PRODUCT_IMAGE_SIZE_THUMBNAIL, true, false); $updates[] = "vcimage = '" . $image->getSourceFilePath() . "'"; $updates[] = "vcimagezoom = '" . $zoom . "'"; $updates[] = "vcimagestd = '" . $standard . "'"; $updates[] = "vcimagethumb = '" . $thumb . "'"; } catch (Exception $ex) { } } if (!empty($updates)) { $updates[] = "vclastmodified = " . time(); $updateSQL = implode(', ', $updates); // update the combinations $query = 'UPDATE [|PREFIX|]product_variation_combinations SET ' . $updateSQL . ' WHERE ' . $whereSQL . $optionSQL; $GLOBALS['ISC_CLASS_DB']->Query($query); } // regenerate the combinations table to get fresh data $html = $this->GetVariationCombinationsTable($filterOptions, true); $response['tableData'] = $html; echo '<textarea>'.isc_json_encode($response).'</textarea>'; exit; }
protected function _ImportRecord($record) { // the field we have chosen to identify the product $prodIdentField = $this->ImportSession['IdentField']; $identFieldName = $this->_ImportFields[$prodIdentField]; // chosen ident field is empty, can't continue if (empty($prodIdentField)) { $this->addImportResult('Failures', GetLang('NoIdentField', array('identField' => $identFieldName))); return; } // get the product for this row $query = "SELECT * FROM [|PREFIX|]products WHERE " . $prodIdentField . " = '" . $GLOBALS['ISC_CLASS_DB']->Quote(trim($record[$prodIdentField])) . "'"; $result = $GLOBALS['ISC_CLASS_DB']->Query($query); if (($prod = $GLOBALS['ISC_CLASS_DB']->Fetch($result)) === false) { // no prod found? failrow $this->addImportResult('Failures', GetLang('AssociatedProductNotFound', array('identField' => $identFieldName, 'identValue' => $record[$prodIdentField]))); return; } $productID = $prod['productid']; $variationID = $prod['prodvariationid']; //---- the fields we'll be updating the product with ---- // variation code if (isset($record['prodvarsku'])) { $prodCode = $record['prodvarsku']; if (!empty($prodCode) || (empty($prodCode) && $this->ImportSession['DefaultForEmpty'])) { $updateFields['vcsku'] = $prodCode; } } elseif (isset($record['prodcode'])) { $prodCode = $record['prodcode']; if (!empty($prodCode) || (empty($prodCode) && $this->ImportSession['DefaultForEmpty'])) { $updateFields['vcsku'] = $prodCode; } } // variation price if (isset($record['prodvarprice'])) { $varPrice = $record['prodvarprice']; if (empty($varPrice) && $this->ImportSession['DefaultForEmpty']) { $updateFields['vcprice'] = 0; $updateFields['vcpricediff'] = ''; } else { // prefixed by a + then it's a price addition if (isc_substr($varPrice, 0, 1) == "+") { $priceDiff = "add"; } // price subtraction elseif ($varPrice < 0) { $priceDiff = "subtract"; } // fixed price else { $priceDiff = "fixed"; } $varPrice = abs((float)DefaultPriceFormat($varPrice)); $updateFields['vcprice'] = $varPrice; $updateFields['vcpricediff'] = $priceDiff; } } // variation weight if (isset($record['prodvarweight'])) { $varWeight = $record['prodvarweight']; if (empty($varWeight) && $this->ImportSession['DefaultForEmpty']) { $updateFields['vcweight'] = 0; $updateFields['vcweightdiff'] = ''; } elseif (!empty($record['prodvarweight'])) { // prefixed by a + then it's a weight addition if (isc_substr($varWeight, 0, 1) == "+") { $weightDiff = "add"; } // weight subtraction elseif ($varWeight < 0) { $weightDiff = "subtract"; } // fixed weight else { $weightDiff = "fixed"; } $updateFields['vcweight'] = abs((float)$varWeight); $updateFields['vcweightdiff'] = $weightDiff; } } // stock level if (isset($record['prodvarstock'])) { if (empty($record['prodvarstock']) && $this->ImportSession['DefaultForEmpty']) { $updateFields['vcstock'] = 0; } else { $updateFields['vcstock'] = $record['prodvarstock']; } } // low stock level if (isset($record['prodvarlowstock'])) { if (empty($record['prodvarlowstock']) && $this->ImportSession['DefaultForEmpty']) { $updateFields['vclowstock'] = 0; } else { $updateFields['vclowstock'] = $record['prodvarlowstock']; } } // enable the option? if (isset($record['prodvarenabled'])) { if (empty($record['prodvarenabled']) && $this->ImportSession['DefaultForEmpty']) { $updateFields['vcenabled'] = 1; } else { $updateFields['vcenabled'] = $this->StringToYesNoInt($record['prodvarenabled']); } } else { // enable by default $updateFields['vcenabled'] = 1; } // variation image if(!empty($record['prodvarimage'])) { // code exists in the new product image management classes to handle these imports $imageFile = $record['prodvarimage']; $imageAdmin = new ISC_ADMIN_PRODUCT_IMAGE; $variationImage = false; // check if this image file (either remote or local) has already been processed on a previous variation, if // so, simply re-use those values instead of re-downloading / re-processing if (isset($this->ImportSession['ImportedImages'][$imageFile])) { $importedImage = $this->ImportSession['ImportedImages'][$imageFile]; if (is_array($importedImage)) { $updateFields = array_merge($updateFields, $importedImage); } } else { $this->ImportSession['ImportedImages'][$imageFile] = false; if (preg_match('#^(?P<scheme>[a-zA-Z0-9\.]+)://#i', $imageFile, $matches)) { // the filename is an external URL, import it against the calcualted product hash $imageAdmin->importImagesFromUrls(false, array($imageFile), $importImages, $importImageErrors, false); if (!empty($importImages)) { $variationImage = $importImages[0]; } if (!empty($importImageErrors)) { // as this import works on one file only and importImagesFromWebUrls creates one error per file, can simply tack on the new error $importImageError = $importImageErrors[0]; if (is_array($importImageError)) { $this->addImportResult('Warnings', $importImageError[1]); } else { $this->addImportResult('Warnings', $importImageError); } } } else { // the filename is a local file $importImageFilePath = ISC_BASE_PATH . "/" . GetConfig('ImageDirectory') . "/import/" . $imageFile; try { $variationImage = ISC_PRODUCT_IMAGE::importImage($importImageFilePath, basename($importImageFilePath), false, false, false, false); } catch (ISC_PRODUCT_IMAGE_SOURCEFILEDOESNTEXIST_EXCEPTION $exception) { // exception message may contain server path; present filtered message and log the original $this->addImportResult('Warnings', GetLang('ProductImageFileDoesNotExist')); trigger_error($exception->getMessage(), E_WARNING); } catch (ISC_PRODUCT_IMAGE_IMPORT_CANTCREATEDIR_EXCEPTION $exception) { // exception message may contain server path; present filtered message and log the original $this->addImportResult('Warnings', GetLang('ImportProductImageFilePermissionIssue')); trigger_error($exception->getMessage(), E_WARNING); } catch (ISC_PRODUCT_IMAGE_IMPORT_CANTMOVEFILE_EXCEPTION $exception) { // exception message may contain server path; present filtered message and log the original $this->addImportResult('Warnings', GetLang('ImportProductImageFilePermissionIssue')); trigger_error($exception->getMessage(), E_WARNING); } catch (Exception $exception) { // other exceptions should be ok to present $this->addImportResult('Warnings', $exception->getMessage()); } } if ($variationImage !== false) { try { $importedImage = array( 'vcimage' => $variationImage->getSourceFilePath(), 'vcimagezoom' => $variationImage->getResizedFilePath(ISC_PRODUCT_IMAGE_SIZE_ZOOM, true, false), 'vcimagestd' => $variationImage->getResizedFilePath(ISC_PRODUCT_IMAGE_SIZE_STANDARD, true, false), 'vcimagethumb' => $variationImage->getResizedFilePath(ISC_PRODUCT_IMAGE_SIZE_THUMBNAIL, true, false), ); $updateFields = array_merge($updateFields, $importedImage); $this->ImportSession['ImportedImages'][$imageFile] = $importedImage; } catch (ISC_PRODUCT_IMAGE_SOURCEFILEDOESNTEXIST_EXCEPTION $exception) { // exception message may contain server path; present filtered message and log the original $this->addImportResult('Warnings', GetLang('ProductImageFileDoesNotExist')); trigger_error($exception->getMessage(), E_WARNING); } catch (ISC_PRODUCT_IMAGE_IMPORT_CANTCREATEDIR_EXCEPTION $exception) { // exception message may contain server path; present filtered message and log the original $this->addImportResult('Warnings', GetLang('ImportProductImageFilePermissionIssue')); trigger_error($exception->getMessage(), E_WARNING); } catch (ISC_PRODUCT_IMAGE_IMPORT_CANTMOVEFILE_EXCEPTION $exception) { // exception message may contain server path; present filtered message and log the original $this->addImportResult('Warnings', GetLang('ImportProductImageFilePermissionIssue')); trigger_error($exception->getMessage(), E_WARNING); } catch (Exception $exception) { // other exceptions should be ok to present $this->addImportResult('Warnings', $exception->getMessage()); } } } } // get the index of the last matched field...we assume that all the remaining fields are variations $lastindex = 0; foreach ($this->ImportSession['FieldList'] as $field => $index) { if ($index > $lastindex) { $lastindex = $index; } } $variationStartIndex = $lastindex + 1; // get the variation fields $variationFields = array_slice($record['original_record'], $variationStartIndex); // split the variation fields into key => value pairs $variationData = array(); foreach ($variationFields as $field) { $varField = explode(":", $field, 2); // ensure we have a key and value...otherwise bad field if (count($varField) != 2) { $this->addImportResult('Failures', GetLang('CantExtractData', array('dataField' => $field))); return; } $varName = trim($varField[0]); $varValue = trim($varField[1]); $variationData[$varName] = $varValue; } // ensure we actually have variation data if (empty($variationData)) { // generate a failure $this->addImportResult('Failures', GetLang('NoVariationData', array('rowNum' => $this->ImportSession['DoneCount'] + 1))); return; } // are we choosing to update an existing variation combination or replacing with a new variation? // make sure this isn't a variation we've created this session if ($this->ImportSession['UpdateExisting'] && $variationID > 0 && !isset($this->ImportSession['NewVariations'][$productID])){ // find the variation options so we can find the combination $query = " SELECT voptionid, voname, vovalue FROM [|PREFIX|]product_variation_options WHERE vovariationid = " . $variationID . " AND ("; $where = ""; foreach ($variationData as $varName => $varValue) { if ($where) { $where .= " OR "; } $where .= " ( voname = '" . $GLOBALS['ISC_CLASS_DB']->Quote($varName) . "' AND vovalue = '" . $GLOBALS['ISC_CLASS_DB']->Quote($varValue) . "' ) "; } $query .= $where . ") ORDER BY vooptionsort, vovaluesort"; $result = $GLOBALS['ISC_CLASS_DB']->Query($query); $optionList = array(); $notFoundOptions = $variationData; // get the option id's if ($GLOBALS['ISC_CLASS_DB']->CountResult($result)) { while ($optionRow = $GLOBALS['ISC_CLASS_DB']->Fetch($result)) { $optionList[] = $optionRow['voptionid']; unset($notFoundOptions[$optionRow['voname']]); } } $updatedName = false; // create any remaining options if (!empty($notFoundOptions)) { foreach ($notFoundOptions as $varName => $varValue) { // find whether it's the option name or value that doesn't exist $query = " SELECT COUNT(*) AS valuecount, vooptionsort, voname FROM [|PREFIX|]product_variation_options WHERE vovariationid = " . $variationID . " AND voname = '" . $GLOBALS['ISC_CLASS_DB']->Quote($varName) . "' GROUP BY voname "; $result = $GLOBALS['ISC_CLASS_DB']->Query($query); // name exists, just create a new value if ($option = $GLOBALS['ISC_CLASS_DB']->Fetch($result)) { $newOption = array( 'vovariationid' => $variationID, 'voname' => $option['voname'], 'vovalue' => $varValue, 'vooptionsort' => $option['vooptionsort'], 'vovaluesort' => $option['valuecount'] + 1 ); $optionID = $GLOBALS['ISC_CLASS_DB']->InsertQuery('product_variation_options', $newOption); array_splice($optionList, $option['vooptionsort'] - 1, 0, $optionID); // we have a new value, we have to create new combinations for each of the rows using the existing data // get existing combinations but exclude the option name that we're on if ($this->ImportSession['CreateAllCombos']) { $combinations = GetVariationCombinations($productID, $varName); foreach ($combinations as $combination) { $newCombination = $combination; // insert the option at correct position array_splice($newCombination, $option['vooptionsort'] - 1, 0, $optionID); $newOptionList = implode(',', $newCombination); // create combination $newCombo = array( 'vcproductid' => $productID, 'vcvariationid' => $variationID, 'vcoptionids' => $newOptionList, 'vcenabled' => 1 ); $GLOBALS['ISC_CLASS_DB']->InsertQuery('product_variation_combinations', $newCombo); } } } else { // name not found, create it with the option // get total option names $query = "SELECT COUNT(DISTINCT voname) AS optioncount FROM [|PREFIX|]product_variation_options WHERE vovariationid = " . $variationID; $result = $GLOBALS['ISC_CLASS_DB']->Query($query); $optioncount = $GLOBALS['ISC_CLASS_DB']->FetchOne($result, 'optioncount'); $newOption = array( 'vovariationid' => $variationID, 'voname' => $varName, 'vovalue' => $varValue, 'vooptionsort' => $optioncount + 1, 'vovaluesort' => 1 ); $optionID = $GLOBALS['ISC_CLASS_DB']->InsertQuery('product_variation_options', $newOption); array_splice($optionList, $optioncount, 0, $optionID); // we have a new option name, so append the new option id to existing combinations $query = " UPDATE [|PREFIX|]product_variation_combinations SET vcoptionids = CONCAT(vcoptionids, '," . $optionID . "') WHERE vcvariationid = " . $variationID; $GLOBALS['ISC_CLASS_DB']->Query($query); // update the variation option count $query = "UPDATE [|PREFIX|]product_variations SET vnumoptions = vnumoptions + 1 WHERE variationid = " . $variationID; $GLOBALS['ISC_CLASS_DB']->Query($query); } } } $optionString = implode(",", $optionList); // attempt to find existing combination again using list of options $query = " SELECT combinationid FROM [|PREFIX|]product_variation_combinations WHERE vcproductid = " . $productID . " AND vcvariationid = " . $variationID . " AND vcoptionids = '" . $optionString . "' "; $result = $GLOBALS['ISC_CLASS_DB']->Query($query); // update the combination if ($comboID = $GLOBALS['ISC_CLASS_DB']->FetchOne($result, 'combinationid')) { $GLOBALS['ISC_CLASS_DB']->UpdateQuery('product_variation_combinations', $updateFields, 'combinationid = ' . $comboID); $this->addImportResult('Updates', $prod['prodname']); } else { // couldn't update an existing combo, create a new one $newCombo = array( 'vcproductid' => $productID, 'vcvariationid' => $variationID, 'vcoptionids' => $optionString ); $newCombo = $newCombo + $updateFields; $GLOBALS['ISC_CLASS_DB']->InsertQuery('product_variation_combinations', $newCombo); $this->ImportSession['Results']['SuccessCount']++; } } else { // create a new variation for this product // have we already created a variation for this product in this import session? if (isset($this->ImportSession['NewVariations'][$productID])) { // we only need to create our new options and the combinations // find any options previously created $thisVar = $this->ImportSession['NewVariations'][$productID]; $thisOptions = array(); $thisOptionsL = array(); foreach ($variationData as $varName => $varValue) { if (isset($thisVar[isc_strtolower($varName)][isc_strtolower($varValue)])) { $thisOptions[$varName] = $thisVar[isc_strtolower($varName)][isc_strtolower($varValue)]; $thisOptionsL[isc_strtolower($varName)] = $thisVar[isc_strtolower($varName)][isc_strtolower($varValue)]; } } // create any remaining uncreated options $remainingOptions = array_diff_key($variationData, $thisOptions); if (!empty($remainingOptions)) { foreach ($remainingOptions as $varName => $varValue) { $lvarName = isc_strtolower($varName); // get the option and value sort numbers // does this option name exist, but just not the value? if (isset($thisVar[$lvarName])) { $keyIndex = array_search($lvarName, array_keys($thisVar)); $optionSort = $keyIndex + 1; $valueSort = count($thisVar[$lvarName]) + 1; } else { $valueSort = 1; $optionSort = count($thisVar) + 1; } $insertOption = array( 'vovariationid' => $variationID, 'voname' => $varName, 'vovalue' => $varValue, 'vooptionsort' => $optionSort, 'vovaluesort' => $valueSort ); $optionID = $GLOBALS['ISC_CLASS_DB']->InsertQuery('product_variation_options', $insertOption); // add this new option to the list $thisVar[$lvarName][isc_strtolower($varValue)] = $optionID; $thisOptionsL[$lvarName] = $optionID; // is it a new option name? if (!$thisVar[isc_strtolower($varName)]) { // we have a new option name, so append the new option id to existing combinations $query = " UPDATE [|PREFIX|]product_variation_combinations SET vcoptionids = CONCAT(vcoptionids, '," . $optionID . "') WHERE vcvariationid = " . $variationID; $GLOBALS['ISC_CLASS_DB']->Query($query); } } } // store options back in session $this->ImportSession['NewVariations'][$productID] = $thisVar; // get the option ids for this combination. they must be in the order that the option names were created. $comboRows = array(array()); foreach ($thisVar as $varName => $varData) { // is there an option that may have already been created but is missing for this record? if (isset($thisOptionsL[$varName])) { foreach ($comboRows as &$combo) { $combo[] = $thisOptionsL[$varName]; } } else { $newRows = array(); // missing option, iterate through all values for that option and create combinations foreach ($comboRows as $combo) { foreach ($varData as $varValue => $optionID) { $newRow = $combo; $newRow[] = $optionID; $newRows[] = $newRow; } } $comboRows = $newRows; } } // insert all our combinations foreach ($comboRows as $thisCombo) { $optionString = implode(",", $thisCombo); // now we can finally create the combination $newCombo = array( 'vcproductid' => $prod['productid'], 'vcvariationid' => $variationID, 'vcoptionids' => $optionString ); $newCombo = $newCombo + $updateFields; $GLOBALS['ISC_CLASS_DB']->InsertQuery('product_variation_combinations', $newCombo); } $this->ImportSession['Results']['SuccessCount']++; } else { // do we have an existing combinations for this product? we should delete any combinations for that first if ($variationID) { $GLOBALS['ISC_CLASS_DB']->DeleteQuery('product_variation_combinations', 'WHERE vcproductid = ' . $productID); } // name of our new variation .. check if it already exists $variationName = $prod['prodname'] . " Variations " . date('dmy'); $query = "SELECT variationid FROM [|PREFIX|]product_variations WHERE vname = '" . $GLOBALS['ISC_CLASS_DB']->Quote($variationName) . "'"; $result = $GLOBALS['ISC_CLASS_DB']->Query($query); if ($varRow = $GLOBALS['ISC_CLASS_DB']->Fetch($result)) { // delete the old variation $GLOBALS['ISC_CLASS_DB']->DeleteQuery('product_variations', 'WHERE variationid = ' . $varRow['variationid']); $GLOBALS['ISC_CLASS_DB']->DeleteQuery('product_variation_options', 'WHERE vovariationid = ' . $varRow['variationid']); $GLOBALS['ISC_CLASS_DB']->DeleteQuery('product_variation_combinations', 'WHERE vcvariationid = ' . $varRow['variationid']); // update products that use this variation $updateProd = array( 'prodvariationid' => 0 ); $GLOBALS['ISC_CLASS_DB']->UpdateQuery('products', $updateProd, 'prodvariationid = ' . $varRow['variationid']); } // create our new variation first $newVariation = array( 'vname' => $variationName, 'vvendorid' => $prod['prodvendorid'] ); $variationID = $GLOBALS['ISC_CLASS_DB']->InsertQuery('product_variations', $newVariation); $this->ImportSession['NewVariationIDs'][$productID] = $variationID; // update our product with the variation ID $updateProd = array( 'prodvariationid' => $variationID ); $GLOBALS['ISC_CLASS_DB']->UpdateQuery('products', $updateProd, 'productid = ' . $productID); $thisVar = array(); $options = array(); // now to create the options $optionCount = 0; foreach ($variationData as $varName => $varValue) { $newOption = array( 'vovariationid' => $variationID, 'voname' => $varName, 'vovalue' => $varValue, 'vooptionsort' => ++$optionCount, 'vovaluesort' => 1 ); $optionID = $GLOBALS['ISC_CLASS_DB']->InsertQuery('product_variation_options', $newOption); $thisVar[isc_strtolower($varName)][isc_strtolower($varValue)] = $optionID; $options[] = $optionID; } $this->ImportSession['NewVariations'][$productID] = $thisVar; // create the combination $optionString = implode(",", $options); $newCombo = array( 'vcproductid' => $productID, 'vcvariationid' => $variationID, 'vcoptionids' => $optionString ); $newCombo = $newCombo + $updateFields; $GLOBALS['ISC_CLASS_DB']->InsertQuery('product_variation_combinations', $newCombo); $this->ImportSession['Results']['SuccessCount']++; } } // a stock or low stock is supplied, enable inventory tracking for the product if (!empty($record['prodvarstock']) || !empty($record['prodvarlowstock'])) { $updateProd = array( 'prodinvtrack' => 2 ); $GLOBALS['ISC_CLASS_DB']->UpdateQuery('products', $updateProd, 'productid = ' . $productID); } /** * This is a bit hackish but we need to update the product last modified time WITHOUT using the * product entity class (shock horror). This is because we have nothing else to update it with */ $savedata = array( "prodlastmodified" => time() ); $GLOBALS["ISC_CLASS_DB"]->UpdateQuery("products", $savedata, "productid = " . $productID); }