It's pretty hard to believe that I've been a expert on Keen/Ingenio for 6 1/2 years now. It's a bit easier to believe that I haven't in-fact posted on this blog in just over 2 years. To be honest, I kinda forgot I even had a blog on Keen but hopefully I'll start posting a bit more.
I like posting things that come up during phone conversations. I had a phone call earlier today from someone doing a class project: the task was to create a pizza ordering system. I've mentioned before that when you code you must always expect the unexpected...and today's advice furthers that topic.
My caller had almost a fully-functioning system. Obviously since this was just a class project it didn't have all the bells and whistles, but it met the requirements for the project. However, almost immediately I noticed a problem.
The orders were being stored in $_SESSION as the user chose each item to add to the cart. The first thing I added was a Small Onion Rings...so the $_SESSION variable looked something like this:
Array
(
[cart] => Array
(
[Onion Rings] => Array
(
[name] => Onion Rings
[size] => Small
[price] => 2.5
[quantity] => 1
[total] => 2.5
)
)
)
See the problem? When items were added to the cart, the name of the item was used as the key for the array. But what problems could that cause?
Expecting the unexpected doesn't just mean "Make sure the information they put in the form is valid"...it also means "Make sure my code produces the expected result no matter what information they put in the form."
So, given that my cart is as above, what would happen if I added 1 Large Onion Rings to my order? Short answer: the Large Onion Rings would replace the Small Onion Rings. Why?
Onion Rings is the name of the product...and that's being used as the key. Whether I choose large or small is neither here nor there...size is a parameter of the product in this case.
So, we redesign our array. Let's modify it so it uses Size as a key as well...and while we're at it, let's get rid of the duplicate information. ONE VERSION OF THE TRUTH! So, the code to add items to the $_SESSION variable looks something like this:
$_SESSION['cart'][$itemName][$itemSize] = array(
'price' => $itemPrice ,
'quantity' => $itemQuantity ,
'total' => $itemTotal
);
Now I can add items of various sizes and they'll all be stored neatly in my array.
Next Question: What happens if I add 1 Small Onion Rings, and then decide to add 2 Small Onion Rings? A better question would be: what will the user EXPECT to happen? In this case, there's three options:
1. Give the user an error message saying that there are already Small Onion Rings in the order and if they'd like to change the quantity they should first remove the Small Onion Rings.
2. Assume that the user made a mistake the first time and REPLACE the 1 Small Onion Rings with the 2 Small Onion Rings.
3. Assume that the user wants MORE Onion Rings so ADD the 2 Small Onion Rings so there's a total of 3.
At this point, you need to throw out what YOU want the system to do and focus on what your user will EXPECT to happen. Whatever the user EXPECTS is by definition the proper behavior. In this case, people expect option #3...that in the end they'd have 3 Onion Rings. Why? Because the button says "Add to Cart". (ADD)
So, I need to add some code like this:
function addItem( $itemName , $itemSize , $itemPrice , $itemQuantity ) {
if ( isset( $_SESSION['cart'][$itemName][$itemSize] ) ) {
$_SESSION['cart'][$itemName][$itemSize]['quantity'] += $itemQuantity;
$_SESSION['cart'][$itemName][$itemSize]['total'] += ( $itemQuantity * $itemPrice );
} else {
$_SESSION['cart'][$itemName][$itemSize] = array(
'price' => $itemPrice ,
'quantity' => $itemQuantity ,
'total' => ( $itemPrice * $itemQuantity )
);
}
}
Now I'm handling it correctly and have ensured that the behavior of my script matches what the user expects to happen. Obviously from here we make sure our "View Cart" screen has the option to remove items and change quantities so users can make changes as they see fit.
Expecting the unexpected might seem tedious...and sometimes it can be. But it's necessary. It might also seem impossible - especially with larger complex projects. You might ask, "How am I supposed to anticipate every possible thing my users might do?"
Well, sometimes you can't! Your job is to anticipate as much as you can...but that's where people like me come in! A fresh pair of eyes can make all the difference in the world. I might think of things that hadn't occurred to you before. So, if you find yourself wanting someone to check over your code and look for gaps, give me a call!