0

I need to calculate a sub total of the items in a shopping cart. It stores the items added to the cart as an array of the product IDs in a session variable.

So to start with I need to use the ID in the cart array to pull the product information from the database (name, price etc.) and then add the prices of all the items in the cart, of which there could be more than one of the same product.

My test cart should have a total price of 96,049.98 but my code is returning a total price of 18. I don't know where it's getting that from.

Here is the code:

function subTotal() {
global $db;
global $table_prefix;
$table = $table_prefix . "products";

foreach($_SESSION['cart'] as $item) {
    $sql = $db->prepare("SELECT * FROM $table WHERE id = :id");
    $sql->bindParam(":id", $item[0]);
    $sql->execute();

    $amount = 0;
    $product = $sql->fetch(PDO::FETCH_ASSOC);
    foreach($product as $price) {
        $amount += $price['price'];
    }
}   
return $amount;
}
1
  • You really should refactor your code. Reuse that prepared statement, don't create it again and again. Also, if you would store ($id => $amount) pairs in your shopping cart, you could reduce your code to using only a single query with an IN clause. And you can get rid of that foreach loop, because a query by id should never return more than one record. Commented May 3, 2013 at 13:27

3 Answers 3

2

You are restarting the value $amount to 0 per iteration.

Try initializating it at the top:

function subTotal() {
global $db;
global $table_prefix;
$table = $table_prefix . "products";
$amount = 0;  //MOVED HERE at the top

foreach($_SESSION['cart'] as $item) {
    $sql = $db->prepare("SELECT * FROM $table WHERE id = :id");
    $sql->bindParam(":id", $item[0]);
    $sql->execute();

    $product = $sql->fetch(PDO::FETCH_ASSOC);
    foreach($product as $price) {
        $amount += $price['price'];
    }
}   
return $amount;
}
Sign up to request clarification or add additional context in comments.

Comments

1

Just take out $amount = 0 out of the loop. As it's getting reset on each product loop.

$amount = 0;
foreach($_SESSION['cart'] as $item) {
    $sql = $db->prepare("SELECT * FROM $table WHERE id = :id");
    $sql->bindParam(":id", $item[0]);
    $sql->execute();    
    $product = $sql->fetch(PDO::FETCH_ASSOC);
    foreach($product as $price) {
        $amount += $price['price'];
    }
} 

3 Comments

That sort of worked, however I am now getting a total of 88 which is still wrong. I don't know where it is getting these figures!
Debug & check you getting all products correctly using var_dum($product);
Nevermind, I've figured it out. I got rid of the second foreach loop and just added $product['amount'].
1

As I mentioned in my comment: In case you are able to change the way your shopping cart stores items, you could refactor your code to something like this:

function subTotal() {
    $db = $GLOBALS['db'];
    $table_prefix = $GLOBALS['table_prefix'];

    $table = $table_prefix . "products";
    $totalPrice = 0;

    // assuming that you actually store ($id => $amount) pairs
    $ids = join(',', array_map('intval', array_keys($_SESSION['cart'])));

    $stmt = $db->prepare("SELECT id, price FROM $table WHERE id IN ($ids)");
    while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
       $amount = $_SESSION['cart'][$row['id']];
       $totalPrice += $amount * $row['price'];
    }

    return $totalPrice;
}

If would assume, that your shopping cart variable would contain something like this:

array(
   4 => 1,   // 1 item with ID 4
   22 => 8   // 8 items with ID 22
)

2 Comments

That would work, however my products have variations that are stored in the cart as well. So there could be two items of the same product and ID, but different variations stored with the individual variant IDs in a multidimensional array with the product.
You could still do a loop first and count how many items of each article is in the cart and then this code would work just as well.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.