CSV stock import for Prestashop 1.6 - php

I would like to create a simple php script that I can run a stock overwrite to my products in Prestashop 1.6. It will need to reference the "product reference" which in my file is "SKU" and then update the "quantity" in Prestashop which is "Available Stock" in my spreadsheet.
At present I am updating this manually every day as I am given a csv file with live stock updates from my supplier. I have seen modules but none of them seem to work for us so hoping theres a simple maybe php script someone has created that would just overwrite the data in the db.
Thanks in advance

Here is an script i use on PS 1.6 for update stock for "product" or "product_attribute" by UPC.
the CSV file in stock/ folder look like :
product ref;stock move;id shop
4443601522;0;1
you can change this scrit to use SKU instead of UPC
<?php
include(dirname(__FILE__) . '/config/config.inc.php');
include(dirname(__FILE__) . '/init.php');
$id_shop = 1;
$id_lang = 1;
$ligne = 0;
$dossier_csv = "/home/mywebsite/public_html/stock/";
echo '<H1>MAJ PS STOCK PAR UPC</h1>';
if (($fic = fopen($dossier_csv . "stock.csv", "a+")) == FALSE) {
echo '<br>Erreur ouverture fichier stock !<br>';
} else {
echo '<h2><u>Traitement des stocks :</u></h2>';
}
while ($tab = fgetcsv($fic, 1024, ';')) {
$champs = count($tab);
$ligne++;
for ($i = 0; $i < $champs; $i++) {
if ($i == 0)
$reference = $tab[$i];
if ($i == 1 && $reference != '' && $ligne != 1) {
$quantity = $tab[$i];
$productId = getIdProductByUPC($reference);
if ($productId != false) {
$idProductAttribute = getIdByUPC($productId, $reference);
$newStock = $quantity;
StockAvailable::setQuantity($productId, $idProductAttribute, $newStock, $id_shop);
echo '<br>(' . $reference . ') : OK qte : <b>' . $quantity . '</b><br>';
} else {
$productId = Product::getIdByUPC($reference);
$product = new Product($productId);
$combination = $product->getAttributeCombinations($id_lang);
if ($productId != false && count($combination) == 0) {
$newStock = $quantity;
StockAvailable::setQuantity($productId, 0, $newStock, $id_shop);
echo '<br>(' . $reference . ') : OK qte : <b>' . $quantity . '</b><br>';
} else {
echo '<br>(' . $reference . '-' . $productId . ') : Erreur enregistrement stock <br>';
}
}
}
}
}
echo '<br><br><br><br>---MAJ TERMINEE---';
function getIdByUPC($id_product, $reference)
{
if (empty($reference)) {
return 0;
}
$query = new DbQuery();
$query->select('pa.id_product_attribute');
$query->from('product_attribute', 'pa');
$query->where('pa.upc LIKE \'%' . pSQL($reference) . '%\'');
$query->where('pa.id_product = ' . (int) $id_product);
return Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue($query);
}
function getIdProductByUPC($reference)
{
if (empty($reference))
return 0;
$query = new DbQuery();
$query->select('pa.id_product');
$query->from('product_attribute', 'pa');
$query->where('pa.upc = \'' . pSQL($reference) . '\'');
return Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue($query);
}
?>

I think, line $productId = Product::getIdByUPC($reference) is wrong.
The correct: $productId = getIdProductByUPC($reference)

Related

Improve CSV products import -> Array Category Query by name

recently we made a big change like build a new category tree for our website, and move over 2M products in the right category.
we have no performance issues, everything runs smoothly.
The only problem I have is that now the category tree is much more complex and deep, and it suffers when adding new articles via CSV import (timeout script, very slow, crash of script)
Basically a new product when it is added by CSV the category field is always textual (separated by "#") example: Engine#Crankshaft#Audi#Audi A5
So where is the problem is in my function for get the categoryID in case alredy exist in the database or not exist. How i can improve? i think the main problem is in the very big array created
protected function _getCategoriesID($field_value)
{
global $Database;
$products_categories = array();
$separator = $this->_getSeparator($field_value);
$category_array = array();
if ($separator != '') {
$category_array = explode($separator, $field_value);
$category_array = array_reverse($category_array);
} else {
$category_array[0] = $field_value;
}
unset($separator);
$Qcategory = $Database->query('select c0.categories_id from :table_categories as c0 inner join :table_categories_description as cd on c0.categories_id=cd.categories_id where cd.categories_name = :categories_name and cd.language_id=:language_id');
$Qcategory->bindTable(':table_categories', TABLE_CATEGORIES);
$Qcategory->bindTable(':table_categories_description', TABLE_CATEGORIES_DESCRIPTION);
$Qcategory->bindValue(':categories_name', $category_array[0]);
$Qcategory->bindInt(':language_id', $this->language);
$count = 1;
if (count($category_array) > 1) {
while ($count < count($category_array)) {
$Qcategory->appendQuery(' and c' . ($count - 1) . '.parent_id in (select c' . $count . '.categories_id from :table_categories' . $count . ' as c' . $count . ' inner join :table_categories_description' . $count . ' as cd' . $count . ' on c' . $count . '.categories_id=cd' . $count . '.categories_id where cd' . $count . '.categories_name = :categories_name' . $count . ' and cd' . $count . '.language_id=:language_id' . $count . ' ');
$Qcategory->bindTable(':table_categories' . $count, TABLE_CATEGORIES);
$Qcategory->bindTable(':table_categories_description' . $count, TABLE_CATEGORIES_DESCRIPTION);
$Qcategory->bindValue(':categories_name' . $count, $category_array[$count]);
$Qcategory->bindInt(':language_id' . $count, $this->language);
$count++;
}
for ($i = 0; $i < $count - 1; $i++) {
$Qcategory->appendQuery(')');
}
}
$Qcategory->execute();
while ($Qcategory->next()) {
$products_categories[] = $Qcategory->value('categories_id');
}
unset($Qcategories);
return $products_categories;
}

Array_push in for loop giving null response

Hello I am trying to push in an array using array_push but I am getting the value of the first index then after that all I am getting a null response, I am not getting where I have done a mistake.I am getting the values properly but in array_push there is some mistake which is in for loop.
Here is my code :
function actioncouponcsv_download() {
$this->layout = false;
foreach (Yii::app()->log->routes as $route) {
if ($route instanceof CWebLogRoute || $route instanceof CFileLogRoute || $route instanceof YiiDebugToolbarRoute) {
$route->enabled = false;
}
}
$dateRange = json_decode($_POST['dateRange'], true);
$start = $dateRange['start'];
$end = $dateRange['end'];
$validity = $_POST['validity'];
$limit = isset($_REQUEST['limit']) && trim($_REQUEST['limit']) ? $_REQUEST['limit'] : 0;
$studio_id = Yii::app()->user->studio_id;
if (isset($_GET['type']) && intval($_GET['type']) ==2) {
$couponobj = new CouponSubscription();
$getcouponobj = $couponobj->getcoupon_data($studio_id,$start,$end,$validity);
$k = 0;
$title_addon = "\t" . "Discount Cycle" . "\t" . "Extend free trail";
$data_addon = "\t" . $getcouponobj[$k]['discount_multiple_cycle'] . "\t" . $getcouponobj[$k]['extend_free_trail'];
} else {
$title_addon = "";
$data_addon = "";
$couponobj = new Coupon();
$getcouponobj = $couponobj->getcoupon_data($studio_id,$limit,1);
}
//$Coupon = Coupon::model()->find('studio_id=:studio_id', array(':studio_id' => $studio_id));
$dataCsv = '';
if ($getcouponobj) {
$headings = "Sl no" . "\t" . "Coupon" . "\t" . "Coupon Type" . "\t" . "Used by a single user" . "\t" . "Valid" . "\t" . "Used" . "\t" . "User" .$title_addon. "\t" . "Used Date". "\t" . "Content Category". "\t" . "Content"."\n";
$i = 1;
$dataCSV[] = Array();
$j = 0;
for ($k = 0; $k < count($getcouponobj); $k++) {
$userList = '-';
if ($getcouponobj[$k]['used_by'] != '0') {
if ($getcouponobj[$k]['coupon_type'] == 1) {
$userList = '';
$userIdList = explode(",", $getcouponobj[$k]['used_by']);
foreach ($userIdList as $userIdListKey => $userIdListVal) {
if ($userIdListKey == 0) {
$userList .= Yii::app()->webCommon->getuseremail($userIdListVal);
} else {
$userList .= " | " . Yii::app()->webCommon->getuseremail($userIdListVal);
}
}
} else {
$userList = Yii::app()->webCommon->getuseremail($getcouponobj[$k]['used_by']);
}
}
if($getcouponobj[$k]['is_all']!=1){
if($getcouponobj[$k]['content_category']==1){
$cont_cat = "Digital";
$content_str = Coupon::model()->getContentInfo($getcouponobj[$k]['specific_content']);
$cont_str = $content_str;
}else if($getcouponobj[$k]['content_category']==2){
$cont_cat = "Physical";
$content_str = Coupon::model()->getContentInfoPhysical($getcouponobj[$k]['specific_content']);
$cont_str = $content_str;
}else{
$cont_cat = "All";
$cont_str = "All";
}
}else{
$cont_cat = "All";
$cont_str = "All";
}
#echo $getcouponobj[$k]['coupon_code'];
array_push($dataCSV[$j],$i);
array_push($dataCSV[$j],$getcouponobj[$k]['coupon_code']);
array_push($dataCSV[$j],(($getcouponobj[$k]['coupon_type'] == 1) ? 'Multi-use' : 'Once-use'));
array_push($dataCSV[$j],(($getcouponobj[$k]['user_can_use'] == 1) ? 'Multiple times' : 'Once'));
array_push($dataCSV[$j],(($getcouponobj[$k]['used_by'] == 0) ? 'Yes' : 'No'));
array_push($dataCSV[$j],(($getcouponobj[$k]['used_by'] == 0) ? '-' : 'Yes'));
array_push($dataCSV[$j],$userList);
array_push($dataCSV[$j],$getcouponobj[$k]['discount_multiple_cycle']);
array_push($dataCSV[$j],$getcouponobj[$k]['extend_free_trail']);
array_push($dataCSV[$j],(($getcouponobj[$k]['cused_date'] == 0) ? '-' : $getcouponobj[$k]['cused_date']));
array_push($dataCSV[$j],$cont_cat);
array_push($dataCSV[$j],$cont_str);
$j++;
//$dataCsv .= $i . "\t" . $getcouponobj[$k]['coupon_code'] . "\t" . (($getcouponobj[$k]['coupon_type'] == 1) ? 'Multi-use' : 'Once-use') . "\t" . (($getcouponobj[$k]['user_can_use'] == 1) ? 'Multiple times' : 'Once') . "\t" . (($getcouponobj[$k]['used_by'] == 0) ? 'Yes' : 'No') . "\t" . (($getcouponobj[$k]['used_by'] == 0) ? '-' : 'Yes') . "\t" . $userList .$data_addon. "\t" . (($getcouponobj[$k]['cused_date'] == 0) ? '-' : $getcouponobj[$k]['cused_date'])."\t" .$cont_cat ."\t".$cont_str."\n";
$i = $i+1;
}
}
print_r(json_encode($dataCSV));
}
PS: I am getting the values. Any help will be highly appreciated.
Well, first thing i see wrong is the way you declare your array:
$dataCSV[] = Array();
$array[] = Means that you are adding a new value to an existing array. To declare your array you should use
$dataCSV = array();
Also, this code:
array_push($dataCSV[$j],$i);
means that you are adding a new value to your $dataCSV[$j] array, but this is never declared as an array, so first thing would be to do
$dataCSV[$j] = new array();
Your code is really long and complicated, those are only examples of issues i see in there.

OSCommerce price schedule inconsistent behaviour

Working on a problem with an "old" shop in OSCommerce. It's a multistore configuration which is tweaked by the previous owner. I have 2 similar products with a price schedule or quantity price break feature.
The problem is 1 of the 2 products is not reacting consistent when added to cart or showing the product page.
1st product: has a price schedule of >5, >10, >20 and >30, with prices from high to low.
2nd product: has the same schedule but is somehow shown the other way around: >30, >20, >10 and >5 with prices from low to high.
The weird thing is that the option sort_order does not exist in the price schedule table so the way that the quantity order is shown is random, but always from high to low or low to high.
The first product shows the correct price in the shopping cart, the second product always shows the highest price at any quantity, where the shopping cart should adjust the price according to the price schedule data.
Done so far without any luck:
Checked the price schedule configuration in backend
Checked product configuration in backend and rechecked in Database
Checked all related database tables
After discovering that the only difference between the products are: product name, product image and product_id, gave the product an product_id close to the working one. Also changed all the related database entry's
Make a copy of the correctly working product and add a price schedule as well.
Here is the code of the class which generates the price_schedule:
<?php
/*
$Id: price_schedule.php,v 1.0 2004/08/23 22:50:52 rmh Exp $
osCommerce, Open Source E-Commerce Solutions
http://www.oscommerce.com
Copyright (c) 2003 osCommerce
Released under the GNU General Public License
*/
/*
price_schedule.php - module to support customer classes with quantity pricing
Originally Created 2003, Beezle Software based on some code mods by WasaLab Oy (Thanks!)
Modified by Ryan Hobbs (hobbzilla)
*/
class PriceFormatter {
var $hiPrice;
var $lowPrice;
var $quantity;
var $hasQuantityPrice;
var $hasSpecialPrice;
var $qtyPriceBreaks;
function PriceFormatter($prices=NULL) {
$this->productsID = -1;
$this->hasQuantityPrice=false;
$this->hasSpecialPrice=false;
$this->hiPrice=-1;
$this->lowPrice=-1;
$this->thePrice = -1;
$this->specialPrice = -1;
$this->qtyBlocks = 1;
$this->qtyPriceBreaks = 0;
if($prices) {
$this->parse($prices);
}
}
function encode() {
$str = $this->productsID . ":"
. (($this->hasQuantityPrice == true) ? "1" : "0") . ":"
. (($this->hasSpecialPrice == true) ? "1" : "0") . ":"
. $this->quantity[1] . ":"
. $this->quantity[2] . ":"
. $this->quantity[3] . ":"
. $this->quantity[4] . ":"
. $this->price[1] . ":"
. $this->price[2] . ":"
. $this->price[3] . ":"
. $this->price[4] . ":"
. $this->thePrice . ":"
. $this->specialPrice . ":"
. $this->qtyBlocks . ":"
. $this->taxClass;
return $str;
}
function decode($str) {
list($this->productsID,
$this->hasQuantityPrice,
$this->hasSpecialPrice,
$this->quantity[1],
$this->quantity[2],
$this->quantity[3],
$this->quantity[4],
$this->price[1],
$this->price[2],
$this->price[3],
$this->price[4],
$this->thePrice,
$this->specialPrice,
$this->qtyBlocks,
$this->taxClass) = explode(":", $str);
$this->hasQuantityPrice = (($this->hasQuantityPrice == 1) ? true : false);
$this->hasSpecialPrice = (($this->hasSpecialPrice == 1) ? true : false);
}
function parse($prices) {
global $customer_group_id, $customer_group_type, $customer_group_discount;
if (!tep_not_null($customer_group_id)) {
$customer_group_id = VISITOR_PRICING_GROUP;
$check_group_query = tep_db_query("select customers_groups_type, customers_groups_discount from " . TABLE_CUSTOMERS_GROUPS . " where customers_groups_id = '" . (int)$customer_group_id . "'");
$check_group = tep_db_fetch_array($check_group_query);
$customer_group_type = $check_group['customers_groups_type'];
$customer_group_discount = $check_group['customers_groups_discount'];
}
$this->productsID = $prices['products_id'];
$this->hasQuantityPrice=false;
$this->hasSpecialPrice=false;
// if ($customer_group_type != '1') {
// $price_schedule_query = tep_db_query("select products_groups_price, products_groups_price_qty FROM " . TABLE_PRODUCTS_PRICE_SCHEDULES . " WHERE products_id = '" . $prices['products_id'] . "' and customers_groups_id = '" . (int)$customer_group_id . "' and stores_id = '" . STORES_ID . "'");
$price_schedule_query = tep_db_query("select products_groups_price, products_groups_price_qty FROM " . TABLE_PRODUCTS_PRICE_SCHEDULES . " WHERE products_id = '" . $prices['products_id'] . "' and stores_id = '" . STORES_ID . "'");
$this->qtyPriceBreaks = tep_db_num_rows($price_schedule_query);
$this->thePrice = $prices['products_price'];
$this->specialPrice = $prices['specials_new_products_price'];
// } else {
// $this->qtyPriceBreaks = 0;
// $this->thePrice = $prices['products_price'] * (100 - $customer_group_discount)/100;
// $this->specialPrice = $prices['specials_new_products_price'];
// if ($this->thePrice < $this->specialPrice) $this->specialPrice = "";
// }
$this->hiPrice = $this->thePrice;
$this->lowPrice = $this->thePrice;
$this->hasSpecialPrice = tep_not_null($this->specialPrice);
$this->qtyBlocks = $prices['products_qty_blocks'];
$this->taxClass=$prices['products_tax_class_id'];
$n = 0;
if ($this->qtyPriceBreaks > 0 ) {
while ($price_schedule = tep_db_fetch_array($price_schedule_query)) {
$this->price[$n]=$price_schedule['products_groups_price'];
$this->quantity[$n]=$price_schedule['products_groups_price_qty'];
if ($this->quantity[$n] == '1') {
$this->thePrice = $this->price[$n];
$this->hiPrice = $this->thePrice;
$this->lowPrice = $this->thePrice;
} else {
$this->hasQuantityPrice = true;
}
$n += 1;
}
}
for($i=0; $i<$this->qtyPriceBreaks; $i++) {
if ($this->hasSpecialPrice == true) {
$this->hiPrice = $this->specialPrice;
if ($this->price[$i] > $this->specialPrice) {
$this->price[$i] = $this->specialPrice;
}
}
if ($this->hasQuantityPrice == true) {
if ($this->price[$i] > $this->hiPrice) {
$this->hiPrice = $this->price[$i];
}
if ($this->price[$i] < $this->lowPrice) {
$this->lowPrice = $this->price[$i];
}
}
}
}
function loadProduct($product_id, $language_id=1)
{
$sql="select pd.products_name, p.products_model, p.products_image, p.products_leadtime, p.products_id, p.manufacturers_id, p.products_price, p.products_weight, p.products_unit, p.products_qty_blocks, p.products_tax_class_id, p.distributors_id, IF(s.status = '1' AND s.stores_id = '" . STORES_ID . "', s.specials_new_products_price, NULL) as specials_new_products_price, IF(s.status = '1' AND s.stores_id = '" . STORES_ID . "', s.specials_new_products_price, p.products_price) as final_price from " . TABLE_PRODUCTS_TO_CATEGORIES . " p2c, ((" . TABLE_PRODUCTS . " p left join " . TABLE_MANUFACTURERS . " m on p.manufacturers_id = m.manufacturers_id, " . TABLE_PRODUCTS_DESCRIPTION . " pd) left join " . TABLE_SPECIALS . " s on p.products_id = s.products_id and s.stores_id = '" . STORES_ID . "') INNER JOIN " . TABLE_PRODUCTS_TO_STORES . " p2s ON p.products_id = p2s.products_id where p2s.stores_id = '" . STORES_ID . "' AND p.products_status = '1' and p.products_id = '" . (int)$product_id . "' and pd.products_id = '" . (int)$product_id . "' and pd.language_id = '". (int)$language_id ."'";
$product_info_query = tep_db_query($sql);
$product_info = tep_db_fetch_array($product_info_query);
$this->parse($product_info);
return $product_info;
}
function computePrice($qty) {
$qty = $this->adjustQty($qty);
$price = $this->thePrice;
if ($this->hasSpecialPrice == true) {
$price = $this->specialPrice;
}
if ($this->hasQuantityPrice == true) {
for ($i=0; $i<$this->qtyPriceBreaks; $i++) {
if (($this->quantity[$i] > 0) && ($qty >= $this->quantity[$i])) {
$price = $this->price[$i];
}
}
}
return $price;
}
// Force QTY_BLOCKS granularity
function adjustQty($qty) {
$qb = $this->getQtyBlocks();
if ($qty < 1) {
$qty = 0;
return $qty;
}
if ($qb >= 1) {
if ($qty < $qb) {
$qty = $qb;
}
if (($qty % $qb) != 0) {
$qty += ($qb - ($qty % $qb));
}
}
return $qty;
}
function getQtyBlocks() {
return $this->qtyBlocks;
}
function getPrice() {
return $this->thePrice;
}
function getLowPrice() {
return $this->lowPrice;
}
function getHiPrice() {
return $this->hiPrice;
}
function hasSpecialPrice() {
return $this->hasSpecialPrice;
}
function hasQuantityPrice() {
return $this->hasQuantityPrice;
}
function getPriceString($style='productPriceInBox') {
global $currencies, $customer_id;
// If you want to change the format of the price/quantity table
// displayed on the product information page, here is where you do it.
if (($this->hasSpecialPrice == true) && ($this->hasQuantityPrice == false)) {
$lc_text = ' <s>' . $currencies->display_price($this->thePrice, tep_get_tax_rate($this->taxClass)) . '</s> <span class="productSpecialPrice">' . $currencies->display_price($this->specialPrice, tep_get_tax_rate($this->taxClass)) . '</span>';
}
if($this->hasQuantityPrice == true) {
$lc_text = '<table align="top" border="0" cellspacing="0" cellpadding="0"><tr><td align="center" colspan="2"><b>' . ($this->hasSpecialPrice == true ? '<s>' . $currencies->display_price($this->thePrice, tep_get_tax_rate($this->taxClass)) . '</s> <span class="productSpecialPrice">' . $currencies->display_price($this->specialPrice, tep_get_tax_rate($this->taxClass)) . '</span> ' : 'vanaf ' . $currencies->display_price($this->lowPrice, tep_get_tax_rate($this->taxClass)) ) . '</b></td></tr>';
for($i=0; $i<=$this->qtyPriceBreaks; $i++) {
if(($this->quantity[$i] > 0) && ($this->price[$i] > $this->specialPrice)) {
$lc_text .= '<tr><td class='.$style.' align="right">> ' . $this->quantity[$i] . ' </td><td class='.$style.'>' . $currencies->display_price($this->price[$i], tep_get_tax_rate($this->taxClass)) . '</td></tr>';
}
}
$lc_text .= '</table>';
} else {
if ($this->hasSpecialPrice == true) {
$lc_text = ' <s>' . $currencies->display_price($this->thePrice, tep_get_tax_rate($this->taxClass)) . '</s> <span class="productSpecialPrice">' . $currencies->display_price($this->specialPrice, tep_get_tax_rate($this->taxClass)) . '</span>';
} else {
$lc_text = ' ' . $currencies->display_price($this->thePrice, tep_get_tax_rate($this->taxClass)) . '';
}
}
// if (VISITOR_PRICING_GROUP < '0' && !tep_session_is_registered('customer_id')) {
// return '';
// } else {
return $lc_text;
// }
}
function getPriceStringShort() {
global $currencies, $customer_id;
if (($this->hasSpecialPrice == true) && ($this->hasQuantityPrice == false)) {
$lc_text = '<div class="priceold">' . $currencies->display_price($this->thePrice, tep_get_tax_rate($this->taxClass)) . '</div><div class="pricenew">' . $currencies->display_price($this->specialPrice, tep_get_tax_rate($this->taxClass)) . '</div>';
} elseif ($this->hasQuantityPrice == true) {
$lc_text = '<div class="vanaf">vanaf</div><div class="price">' . $currencies->display_price($this->lowPrice, tep_get_tax_rate($this->taxClass)) . ' </div>';
} else {
$lc_text = '<div class="price">' . $currencies->display_price($this->thePrice, tep_get_tax_rate($this->taxClass)) . '</div>';
}
// if (VISITOR_PRICING_GROUP < '0' && !tep_session_is_registered('customer_id')) {
// return TEXT_LOGIN_TO_SEE_PRICES;
// } else {
return $lc_text;
// }
}
}
?>
I'm not experienced enough to decipher the class and find strange things, if you need more info, do not hesitate to ask.
Any help would be apreciated.
As I understand your question, you would like the product prices to be ordered consistently. I'm aware of the addons you mention but I'm not very familiar with them. That being said you can try to change this line...
$price_schedule_query = tep_db_query("select products_groups_price, products_groups_price_qty FROM " . TABLE_PRODUCTS_PRICE_SCHEDULES . " WHERE products_id = '" . $prices['products_id'] . "' and stores_id = '" . STORES_ID . "'");
to
$price_schedule_query = tep_db_query("select products_groups_price, products_groups_price_qty FROM " . TABLE_PRODUCTS_PRICE_SCHEDULES . " WHERE products_id = '" . $prices['products_id'] . "' and stores_id = '" . STORES_ID . "'" . " ORDER BY products_groups_price ASC");
As I said, I'm not familiar with exactly how the addons you mentioned work but I'd start by adding ordering to the mysql query. This approach has worked for me on numerous occasions with various addons.

How To Change Numbers Based On Results

I have a follow up question on something I got help with here the other day (No Table Three Column Category Layout).
The script is as follows:
$res = mysql_query($query);
$system->check_mysql($res, $query, __LINE__, __FILE__);
$parent_node = mysql_fetch_assoc($res);
$id = (isset($parent_node['cat_id'])) ? $parent_node['cat_id'] : $id;
$catalist = '';
if ($parent_node['left_id'] != 1)
{
$children = $catscontrol->get_children_list($parent_node['left_id'], $parent_node['right_id']);
$childarray = array($id);
foreach ($children as $k => $v)
{
$childarray[] = $v['cat_id'];
}
$catalist = '(';
$catalist .= implode(',', $childarray);
$catalist .= ')';
$all_items = false;
}
$NOW = time();
/*
specified category number
look into table - and if we don't have such category - redirect to full list
*/
$query = "SELECT * FROM " . $DBPrefix . "categories WHERE cat_id = " . $id;
$result = mysql_query($query);
$system->check_mysql($result, $query, __LINE__, __FILE__);
$category = mysql_fetch_assoc($result);
if (mysql_num_rows($result) == 0)
{
// redirect to global categories list
header ('location: browse.php?id=0');
exit;
}
else
{
// Retrieve the translated category name
$par_id = $category['parent_id'];
$TPL_categories_string = '';
$crumbs = $catscontrol->get_bread_crumbs($category['left_id'], $category['right_id']);
for ($i = 0; $i < count($crumbs); $i++)
{
if ($crumbs[$i]['cat_id'] > 0)
{
if ($i > 0)
{
$TPL_categories_string .= ' > ';
}
$TPL_categories_string .= '' . $category_names[$crumbs[$i]['cat_id']] . '';
}
}
// get list of subcategories of this category
$subcat_count = 0;
$query = "SELECT * FROM " . $DBPrefix . "categories WHERE parent_id = " . $id . " ORDER BY cat_name";
$result = mysql_query($query);
$system->check_mysql($result, $query, __LINE__, __FILE__);
$need_to_continue = 1;
$cycle = 1;
$column = 1;
$TPL_main_value = '';
while ($row = mysql_fetch_array($result))
{
++$subcat_count;
if ($cycle == 1)
{
$TPL_main_value .= '<div class="col'.$column.'"><ul>' . "\n";
}
$sub_counter = $row['sub_counter'];
$cat_counter = $row['counter'];
if ($sub_counter != 0)
{
$count_string = ' (' . $sub_counter . ')';
}
else
{
if ($cat_counter != 0)
{
$count_string = ' (' . $cat_counter . ')';
}
else
{
$count_string = '';
}
}
if ($row['cat_colour'] != '')
{
$BG = 'bgcolor=' . $row['cat_colour'];
}
else
{
$BG = '';
}
// Retrieve the translated category name
$row['cat_name'] = $category_names[$row['cat_id']];
$catimage = (!empty($row['cat_image'])) ? '<img src="' . $row['cat_image'] . '" border=0>' : '';
$TPL_main_value .= "\t" . '<li>' . $catimage . '' . $row['cat_name'] . $count_string . '</li>' . "\n";
++$cycle;
if ($cycle == 7) // <---- here
{
$cycle = 1;
$TPL_main_value .= '</ul></div>' . "\n";
++$column;
}
}
if ($cycle >= 2 && $cycle <= 6) // <---- here minus 1
{
while ($cycle < 7) // <---- and here
{
$TPL_main_value .= ' <p> </p>' . "\n";
++$cycle;
}
$TPL_main_value .= '</ul></div>'.$number.'
' . "\n";
}
I was needing to divide the resulting links into three columns to fit my html layout.
We accomplished this by changing the numbers in the code marked with "// <---- here".
Because the amount of links returned could be different each time, I am trying to figure out how to change those numbers on the fly. I tried using
$number_a = mysql_num_rows($result);
$number_b = $number_a / 3;
$number_b = ceil($number_b);
$number_c = $number_b - 1;
and then replacing the numbers with $number_b or $number_c but that doesn't work. Any ideas?
As mentioned before, you can use the mod (%) function to do that.
Basically what it does is to get the remainder after division. So, if you say 11 % 3, you will get 2 since that is the remainder after division. You can then make use of this to check when a number is divisible by 3 (the remainder will be zero), and insert an end </div> in your code.
Here is a simplified example on how to use it to insert a newline after every 3 columns:
$cycle = 1;
$arr = range (1, 20);
$len = sizeof ($arr);
for ( ; $cycle <= $len; $cycle++)
{
echo "{$arr[$cycle - 1]} ";
if ($cycle % 3 == 0)
{
echo "\n";
}
}
echo "\n\n";

Is there a better loop I could write to reduce database queries?

Below is some code I've written that is effective, but makes too many database queries. Is there a way I could optimize and reduce the number of queries but have conditional statements still be as effective as below?
I pasted the code repeated a few times just for good measure.
echo "<h3>Pool Packages</h3>";
echo "<ul>";
foreach ($items as $item):
$this->db->where('id', $item['id']);
$query = $this->db->get('items')->row();
if ($item['quantity'] > 1 && $item['quantity'] == TRUE && $query->category == "Pool Packages") {
$newprice = $item['quantity'] * $query->price;
$totals[] = $newprice;
}
else {
$newprice = $query->price;
$totals[] = $newprice;
}
if ($query->category == "Pool Packages") {
echo "<li>" . $query->name . " (QTY: " . $item['quantity'] . " x = " . str_ireplace(" ", "", money_format('%(#10n', $newprice)) . ")</li>";
}
else { }
endforeach;
echo "</ul>";
echo "<h3>Water Features</h3>";
echo "<ul>";
foreach ($items as $item):
$this->db->where('id', $item['id']);
$query = $this->db->get('items')->row();
if ($item['quantity'] > 1 && $item['quantity'] == TRUE && $query->category == "Water Features") {
$newprice = $item['quantity'] * $query->price;
$totals[] = $newprice;
}
else {
$newprice = $query->price;
$totals[] = $newprice;
}
if ($query->category == "Water Features") {
echo "<li>" . $query->name . " (QTY: " . $item['quantity'] . " x = " . str_ireplace(" ", "", money_format('%(#10n', $newprice)) . ")</li>";
}
else { }
endforeach;
echo "</ul>";
echo "<h3>Waterfall Rock Work</h3>";
echo "<ul>";
foreach ($items as $item):
$this->db->where('id', $item['id']);
$query = $this->db->get('items')->row();
if ($item['quantity'] > 1 && $item['quantity'] == TRUE) {
$newprice = $item['quantity'] * $query->price;
$totals[] = $newprice;
}
else {
$newprice = $query->price;
$totals[] = $newprice;
}
if ($query->category == "Waterfall Rock Work") {
echo "<li>" . $query->name . " (QTY: " . $item['quantity'] . " x = " . str_ireplace(" ", "", money_format('%(#10n', $newprice)) . ")</li>";
}
else { }
endforeach;
echo "</ul>";
echo "<h3>Sheer Descents</h3>";
echo "<ul>";
foreach ($items as $item):
$this->db->where('id', $item['id']);
$query = $this->db->get('items')->row();
if ($item['quantity'] > 1 && $item['quantity'] == TRUE && $query->category == "Sheer Descents") {
$newprice = $item['quantity'] * $query->price;
$totals[] = $newprice;
}
else {
$newprice = $query->price;
$totals[] = $newprice;
}
if ($query->category == "Sheer Descents") {
echo "<li>" . $query->name . " (QTY: " . $item['quantity'] . " x = " . str_ireplace(" ", "", money_format('%(#10n', $newprice)) . ")</li>";
}
else { }
endforeach;
echo "</ul>";
echo "<h3>Booster Pump</h3>";
echo "<ul>";
foreach ($items as $item):
$this->db->where('id', $item['id']);
$query = $this->db->get('items')->row();
if ($item['quantity'] > 1 && $item['quantity'] == TRUE && $query->category == "Booster Pump") {
$newprice = $item['quantity'] * $query->price;
$totals[] = $newprice;
}
else {
$newprice = $query->price;
$totals[] = $newprice;
}
if ($query->category == "Booster Pump") {
echo "<li>" . $query->name . " (QTY: " . $item['quantity'] . " x = " . str_ireplace(" ", "", money_format('%(#10n', $newprice)) . ")</li>";
}
else { }
endforeach;
echo "</ul>";
echo "<h3>Pool Concrete Decking</h3>";
echo "<ul>";
foreach ($items as $item):
$this->db->where('id', $item['id']);
$query = $this->db->get('items')->row();
if ($item['quantity'] > 1 && $item['quantity'] == TRUE && $query->category == "Pool Concrete Decking") {
$newprice = $item['quantity'] * $query->price;
$totals[] = $newprice;
}
else {
$newprice = $query->price;
$totals[] = $newprice;
}
if ($query->category == "Pool Concrete Decking") {
echo "<li>" . $query->name . " (QTY: " . $item['quantity'] . " x = " . str_ireplace(" ", "", money_format('%(#10n', $newprice)) . ")</li>";
}
else { }
endforeach;
echo "</ul>";
echo "<h3>Solar Heating</h3>";
echo "<ul>";
foreach ($items as $item):
$this->db->where('id', $item['id']);
$query = $this->db->get('items')->row();
if ($item['quantity'] > 1 && $item['quantity'] == TRUE && $query->category == "Solar Heating") {
$newprice = $item['quantity'] * $query->price;
$totals[] = $newprice;
}
else {
$newprice = $query->price;
$totals[] = $newprice;
}
if ($query->category == "Solar Heating") {
echo "<li>" . $query->name . " (QTY: " . $item['quantity'] . " x = " . str_ireplace(" ", "", money_format('%(#10n', $newprice)) . ")</li>";
}
else { }
endforeach;
echo "</ul>";
echo "<h3>Raised Bond Beam</h3>";
echo "<ul>";
foreach ($items as $item):
$this->db->where('id', $item['id']);
$query = $this->db->get('items')->row();
if ($item['quantity'] > 1 && $item['quantity'] == TRUE && $query->category == "Raised Bond Beam") {
$newprice = $item['quantity'] * $query->price;
$totals[] = $newprice;
}
else {
$newprice = $query->price;
$totals[] = $newprice;
}
if ($query->category == "Raised Bond Beam") {
echo "<li>" . $query->name . " (QTY: " . $item['quantity'] . " x = " . str_ireplace(" ", "", money_format('%(#10n', $newprice)) . ")</li>";
}
else { echo "<li>None</li>"; }
endforeach;
echo "</ul>";
It goes on beyond this to several more categories, but I don't know how to handle looping through this best. Thanks!
You could build the html in a variable so you only loop once. Here's a quick and dirty example just to show you what I'm talking about:
$html = '';
$oldCat = '';
foreach ($items as $item) {
$this->db->where('id', $item['id']);
$query = $this->db->get('items')->row();
if ($oldCat != $query->category) {
$html .= "</ul>\n";
$html .= "<h3>".$query->category."</h3>\n<ul>\n";
$oldCat = $query->category;
}
if ($item['quantity'] > 0) {
$newprice = $item['quantity'] * $query->price;
$totals[] = $newprice;
}
$html .= "<li>" . $query->name . " (QTY: " . $item['quantity'] . " x = " . str_ireplace(" ", "", money_format('%(#10n', $newprice)) . ")</li>\n";
}
// strip leading /ul, append a /ul, echo html
You could store all the rows into a separate array during the first loop and then reference the array throughout all the other loops rather than fetching the same information over and over, assuming you're select * which you probably are.
Or, if there are not many items more than the ones you're fetching, you could use a single query to fetch all of the rows at once (you're using only one query) and loop through that to store all the values in an array $array[$row['id']] = $row (or something similar) then simply reference all those rows in the array in each of your loops.
You need to start thinking in terms of sets instead of loops. Write a stored proc that takes the array either as a varchar (or in SQL Server 2008 you can use a table valued input parameter, don't know about other dbs).
Then split the string into a temp table and return all the records in one select joining to the temp table. Even if you need to return separate record sets, doing it in a stored proc will reduce the network traffic in.
you should use a join from items to category and get all the items, then you can sort them out into a multi-dimensional array and then loop through that for output.
Im not sure what youre classes db connection is doing but but lets assume we want all items with thier category:
$sql = "SELECT item.*, category.name as category from item, category WHERE item.category_id = category.item_id";
// ill use PDO for db access here...
$db = new PDO($connString, $username, $password);
$items = array(); // our array indexed by category.
foreach($db->query($sql) as $item) {
if(!array_key_exists($items, $item['category']) {
$items[$item['category']] = array();
}
$items[$item['category']][] = $item;
}
// now loop through $items using the similar stuff you did for output previously.
// note instead of doing the conditionals for pricing and stuff here you may want to
// do that in the loop above and put it in the array before hand... it will keep the
// output loop cleaner.

Categories