I'm building a shopping cart, I save the orders in a multidimensional array which is stored in a session, $_SESSION['cart']
A product is represented by something like
$product_array=array($id,$description,$price);
The multidimensional array is the array of the $product_array.s
The $id's are unique.
The issue is, When i want to remove a product from the multidimensional $_SESSION['cart']
array based on the id, it works if it's just one item in the cart, but if more, it doesn't work, the items seems to be removed but it's 'ghost' is left behind in the cart. The code
is something like this :
//get $id, $count is elements in array
for ($r = 0; $r <= $count-1; $r++)
{
if($_SESSION['cart'][$r][0]=="$id")
{
unset($_SESSION['cart'][$r]);
echo "<div class=success>The item has been removed from your shopping cart.</div>";
break;
}
}
try this one function and that is working for me
function remove_product($id){
$id=intval($id);
$max=count($_SESSION['cart']);
for($i=0;$i<$max;$i++){
if($id==$_SESSION['cart'][$i]['id']){
unset($_SESSION['cart'][$i]);
break;
}
}
$_SESSION['cart']=array_values($_SESSION['cart']);
if($_REQUEST['command']=='delete' && $_REQUEST['id']>0){
remove_product($_REQUEST['id']);
}
else if($_REQUEST['command']=='clear'){
unset($_SESSION['cart']);
}
else if($_REQUEST['command']=='update'){
$max=count($_SESSION['cart']);
for($i=0;$i<$max;$i++){
$id=$_SESSION['cart'][$i]['id'];
$q=intval($_REQUEST['qty'.$id]);
if($q>0 && $q<=999){
$_SESSION['cart'][$i]['qty']=$q;
}
else{
$msg='Some proudcts not updated!, quantity must be a number between 1 and 999';
}
}
}
Check if register_global is on in your php.conf. Try to use following syntax to unset both:
if($_SESSION['cart'][$r][0]=="$id") {
$_SESSION['cart'][$r] = NULL;// this is just to be sure =)
unset($_SESSION['cart'][$r], $cart[$r]);
echo "<div class=success>The item has been removed from your shopping cart.</div>";
break;
}
The following code works, maybe it will help You find what's wrong with Yours:
session_start();
$i=0;
$_SESSION['cart'][]=array($i++,'sds',99);
$_SESSION['cart'][]=array($i++,'sds',100);
$_SESSION['cart'][]=array($i++,'sds',20);
$_SESSION['cart'][]=array($i++,'sds',10);
$id = 2;
$count = count($_SESSION['cart']);
for ($r=0;$r<$count;$r++)
{
echo "num=$r<br>";
if(isset($_SESSION['cart'][$r]) && $_SESSION['cart'][$r][0]==$id)
{
unset($_SESSION['cart'][$r]);
echo "The item has been removed from your shopping cart.<br>";
break;
}
}
session_write_close();
As stated I think the issue has to do with the layout of your array and what you try to check against in your for loop or perhaps some PHP setting. Have you initiated a session for example? I would probably move to use an array of product references. Working with plain arrays can quickly become a nightmare where you accidently reference the wrong object without any kind of warning etc. Encapsulated objects fetched with well formed function names helps avoid this.
Something like
$cart = array($productId => $quantity, $productId2 => $quantityOfSecondProduct);
And then have an array that has all the product info data
$products = array($product1...);
where each product is of the type
class Product
{
$productId;
$productName;
$productDescription;
... etc
}
Then you have all the data separated but easily accessible and you can delete one or more entries in the cart based on the products id easily but just referencing it and deleting if quantity is 0.
if(($cart[$productId] - $quantityToRemove) <= 0)
unset($cart[$productId]);
else
$cart[$productId] -= $quantityToRemove;
Note that filling the products etc should preferably be done from some data source, I would also have put the entire cart as a class with nice functions and a bit more error checking should be in place ;)
Related
I can't think my way through this one. I'm still learning arrays so go easy on me. I'm using codeigniter.
I have 3 tabs (1 month, 2 month, 3 month) in my mark-up.
Each tab shows 3 price boxes (3 levels - basic=1, standard=2, featured=3).
I need to display 9 prices overall, pulled from 1 look-up:
return $this->db->get('prices')->result_array();
In the database it's like this
Should I be trying to do it from one look-up as shown in my model or should I be doing several look-ups, or should I just be managing that look-up in the controller setting vars, ready to display in the view or just doing everything in the view? And How? The only think of 3x foreach loops, where inside the loop I say:
if($prices['months']==3) echo $prices['level'].' is '.$prices['amount'].'<br>';
I'd like to know the BEST way to do this but also how to do the array from one look-up, because I think I really need to get my head around arrays properly. Thanks :)
-- EDIT to show what I've ended up using below --
In the controller, sort of inspired by array_chunk but more manual and to allow for the table to expand, is setting array keys which I read up on in php manual:
foreach ($prices as $price_row) {
$data['prices'][$price_row['months']][] = $price_row;
}
Then in the view I can just use foreach for a month:
foreach ($prices[1] as $p) {
echo level_name($p['level']).' = '.$p['amount'].'<br>';
}
i did not test this so might have made a stupid error - but basically you can foreach through each of your products - make an array - and then use that array in your view.
// in your model Note I am returning an object not an array
// and always check to make sure something got returned
if( ! $products = $this->db->get('prices')->result() )
{
return false:
}
else
{
$prices = array();
foreach($products as $product)
{
// append the months number to the word 'months' to make it clear
$month = $product->months . 'month' ;
// same with level
$level = 'level' . $product->level ;
// build the array
$prices[$month][$level] = $product->amount ;
}//foreach
return $prices ;
}//else
so then in your controller - make sure something came back from the model, assign it to data, then pass data to your view
if( ! $data['prices'] = $this->somemodelname->returnPrices() )
{
$this->showError() ;
}
else
{
$this->load->view('yourviewname', $data);
}
and then in your view you could foreach or just echo out each price if it needs to follow some layout.
echo '1 month level 1 $' . $prices['1month']['level1'] ;
and remember your best friend when doing arrays is print_r wrapped in pre tags so like
echo 'start prices <br> <pre>' ;
print_r($prices) ;
echo '</pre>' ;
opinions - its fine to build stuff in the controller and the view while you are developing and building out. but get in the habit of refactoring to your models. keep your controllers as clean and thin as possible. if your views need complicated data structures - build them in a model first. that way if something goes wrong - your controller can decide what to do. AND you don't have to check in your view if $prices is set and valid because you have already done it. this minimizes where things can go wrong.
Here's a pretty easy way to sort the db return into separate arrays and then display them. #caralot stole my thunder so I came up with this alternative.
Using your current model return $this->db->get('prices')->result_array(); and assigning it to $data.
$data = $this->db->functionName();
//You should check $data validity but I'm skipping that
$month1 = [];
$month2 = [];
$month3 = [];
foreach($data as $row)
{
if($row['months'] === '1')
{
$month1[] = $row;
}
elseif($row['months'] === '2')
{
$month2[] = $row;
}
else
{
$month3[] = $row;
}
}
echo "Month 1<br>";
foreach($month1 as $month){
echo "Level ". $month['level'].' is '.$month['amount'].'<br>';
}
echo "Month 2<br>";
foreach($month2 as $month){
echo "Level ".$month['level'].' is '.$month['amount'].'<br>';
}
echo "Month 3<br>";
foreach($month3 as $month){
echo "Level ".$month['level'].' is '.$month['amount'].'<br>';
}
If your table was less ordered than what you show it would be necessary to add a $this->db->order_by('level', 'ASC'); call to the query.
It is such a tiny dataset that you should definitely do a single lookup. Sorting the array into three arrays in your controller would make more sense as it will leave your view much cleaner, and allow you to set defaults should there be no data (say level 1 for 3 months is removed) if you need to. You are always going to need three foreach loops unless you construct the entire table in one go, setting breaks and new column headings when the level indicator changes.
There is no 'Best' way to do this, it is all case dependent on complexity of layout, future data development and your requirements. Usually though you minimize the number of queries, and keep data manipulation to a minimum within you views. So ideally you will have three arrays, one for each column, sent to your view.
In your controller,
$result = $this->db->query("SELECT * from prices");
$result=$result->result();
$tab1=array();
$tab2=array();
$tab3=array();
foreach ($result as $res) {
switch($res->months)
{
case 1: array_push($tab1, $res);
break;
case 2: array_push($tab2, $res);
break;
case 3: array_push($tab3, $res);
break;
}
}
//var_dump($tab3); //array tab1 for month1, array tab2 for month2, array tab3 for month3
$data['tab1']=$tab1;
$data['tab2']=$tab2;
$data['tab3']=$tab3;
$data['include']=$this->load->view('myview', $data);
In your view i.e myview in my case,
<?php
if(!empty($tab1))
{
echo "Tab 1"."<br>";
foreach($tab1 as $tb)
{
echo "For level ".$tb->level." price is ".$tb->amount."<br>";
}
}
if(!empty($tab2))
{
echo "Tab 2"."<br>";
foreach($tab2 as $tb)
{
echo "For level ".$tb->level." price is ".$tb->amount."<br>";
}
}
if(!empty($tab3))
{
echo "Tab 3"."<br>";
foreach($tab3 as $tb)
{
echo "For level ".$tb->level." price is ".$tb->amount."<br>";
}
}
?>
I have piece of code that I need to use echo function in order to print the variables inside the session array, on the other hand I need to add prices one by one every time user chooses a product. The prices variable is a string. The code as follows:
if (!is_array($_SESSION['products']['names'])){
$_SESSION['products']['names']['name'] = array();
$_SESSION['products']['names']['prices']= array();
}else {
$pros = $_SESSION['products']['names']['name'];
if (in_array($product->getName(), $pros, true)){
echo 'The product is available in your basket';
} else {
$prozuct = array_push($_SESSION['products']['names']['name'],$product->getName());
array_push($_SESSION['products']['names']['prices'], $product->getPrice(Currency::getCurrentCurrency()));
foreach ($_SESSION['products'] as $id=>$arr){
for ($i=0;$i<count($arr);$i++){
echo $arr['name'][$i];
}
}
}
}
The error that I receive is:
Notice: Undefined offset: 1 in /Users
And additionally I know that I can use print_r but in my case I want to add prices one by one and calculate and show the total of amount to user.
No need for a loop:
$namesHtml = implode("<br>", $_SESSION['products']['names']['name']);
$total = array_sum($_SESSION['products']['names']['price']);
echo sprintf("<p>Products: <br>%s<br>Total Cost: %s", $namesHtml, $total);
My simple shopping cart stores products id's in a session array.
I'm trying to set up an if/else statement to enable/disable my "Add to cart" button based on the product ID being in array or not.
<?php
session_start();
//Show cart array
print_r($_SESSION['cart']);
echo '<br><br>';
//Return "yes" or "no"
$panier = $_SESSION['cart'];
$produit = "5";
if (in_array($produit, $panier)) {
print "yes man!";
}
else {
print "no man!";
}
?>
I'm making sure 5 is part of the array values by displaying them of this test page, but the second part always returns "no man!"
looks simple enough to me. What am i doing wrong ?
print_r command output is
5,5
no man!
that is because i've added 2 of the "5" product id to my cart
If I change this line
print_r($_SESSION['cart']);
for
print_r($_SESSION);
I get
Array ( [cart] => 5,3,3,3,3,3,3,3,2 )
no man!
So, according to you, $_SESSION['cart'] = "5,5"; and it means it is a string. So the right code to look up your value is strpos():
$pos = strpos($produit, $_SESSION['cart']);
if($pos !== false) {
echo "YES";
}
else {
echo "NO";
}
BUT there's a huge risk to get the wrong answer for this. Imagine, you have two products in your cart - first with id 15 and the other with id 7. You'll be looking for id 5. What would the above code output? It will output "YES".
So, instead of using a string, I suggest you use multidimensional array (if you want to stick with sessions). In this particular case then, the variable $_SESSION["cart"] would be an array and with adding new products it would look like this:
$_SESSION["cart"] = array(); // initial value, don't call it every time or it'll flush your array
$_SESSION["cart"][] = $product_ID;
Or similar to it.
print_r will give you a similarly-looking output:
Array(
cart => array(
[0] => 5
[1] => 17
[2] => 5
)
)
Then, in_array should work. But, plan your storing wisely ;)
As jon asked it is better put always the output of your program But for now I am suspecting your problem is in the in_array check this link A problem about in_array it might help
I'm trying to add a new variable (argument) `$sugg_only = false' to the get_lists method. Right now I'm pulling all my data based on if the user has a sign in token. This works fine and returns the array of data on their custom list.
What I'm trying to do is return stuff from their shopping_list_name if the Suggested column is set to Y. This way if they don't have a custom list it will pull a suggested list that we provide.
Here’s the full list of what’s in the table:
ID SHOPPING_LIST_NAME S SEQUENCE
1 test amnaik shopping list N
2 bonner shopping list N
3 793d7384fa4fa247d6fae07db104147d0a2dad6e Y
4 kj's shopping list N
5 kj's shopping list from 1384201636 N
6 kj's shopping list from 1384201659 N
7 kj's shopping list from 1384202055 N
8 kj's shopping list from 1384202089 N
9 kj's shopping list from 1385064064 N
10 kj's shopping list from 1385064145 N
11 kj's shopping list from 1385064150 N
12 kj's shopping list from 1385064257 N
13 kj's shopping list from 1385064825 N
14 kj's shopping list from 1385064857 N
So, as you see, there’s just one (terribly named) shopping list that’s setup as a suggestion.
// Get a user's shopping lists
public function get_lists($clobber = false, $sugg_only = false) {
if ($this->UserShoppingList != null && !$clobber) {
return $this->UserShoppingList;
} else if ($this->get_sign_in_token()) {
global $db;
$vars = array();
$vars[] = array(':i_sign_in_token', strtoupper($this->get_sign_in_token()));
$rows = $db->get_function_ref_cursor('custom.japi_shopping_list.get_lists_for_shopper(:i_sign_in_token)', $vars);
// Turn the rows into objects and get their items.
foreach ($rows as $row) {
$list = new UserShoppingList(null, $this->sign_in_token);
$list->get_from_array($row);
$list->get_items();
$this->UserShoppingList[] = $list;
}
return $this->UserShoppingList;
} else {
return false;
}
}
api page:
if(!isset($_GET['token']) && !isset($_GET['suggested_only'])) {
die('Must pass-in either a \'token\' or \'suggested_only\' flag');
}
if(isset($_GET['token'])) {
$shopper = new Shopper($_GET['token'])
or die('Could not instantiate a new Shopper from the \'token\' passed-in');
$array = array();
$shopper_lists = $shopper->get_lists(true);
foreach ($shopper_lists as $list) {
$array[] = $list->json();
}
echo json_encode($array);
// echo json_encode($shopper_lists);
}
Will i likely be writing another foreach loop and just including whatever happens if $sugg_only is equal to TRUE??
add something like so to the bottom of my api page??:
if(isset($_GET['suggested_only']) && $_GET['suggested_only'] == 'true')
{
}
Any help would be greatly appreciated. Thank you.
When dealing with arrays I'll usually favour array_key_exists('suggested_only', $_GET) over isset($_GET['suggested_only'])
If there's nothing really different with the execution of the data, just a difference in the data you are selecting, I'd put your statement at the TOP of the API page, not the bottom.
That way, your IF statement can define a flag for when you inevitably call $shopper->get_lists()
You could do something like this:
$suggestions = false;
$clobber = false;
if(isset($_GET['suggested_only']) && $_GET['suggested_only'] == 'true')
{
$suggestions = true;
}
...
$shopper_lists = $shopper->get_lists($clobber, $suggestions);
This way, you don't really duplicate code fetching the data you want.
HOWEVER
When it comes down to it, what if you add a whole series of types of lists to get. You don't want to add a flag and another variable to your get_lists function. It would become a mess.
It would be better to have a single variable like $_GET['type'], and switch it as follows:
switch($_GET['type'])
{
case 'thingo':
$shopper->get_lists('thingo');
//Or you could use $shopper->get_thingo_list();
break;
case 'suggestion':
$shopper->get_lists('suggestion');
//Or you could use $shopper->get_suggestion_list();
break;
case 'list':
$shopper->get_lists('list');
//Or you could use $shopper->get_list();
break;
default:
//No type exists here
break;
}
Some people might suggest to just pass the $_GET variable straight to your function, but I always get a bit nervous doing that for security reasons.
there is a $_SESSION array that holds the ID of user's currently selected products (which are in the cart). Now, when the user sees his bill, he want to remove an item (product) from his cart, I have put him a link to do so. but the script does not work.
I have configured a $_GET['itemid'] in the URL and by using it, I unset() that array element.
BUT it does not work. What should I do? Here is my code
function remove_from_cart($stack_id) // stack_id is the id of the item in cart array ($_SESSION)
{
for($i=0; $i < count($_SESSION['add-to-cart-item']); $i++)
{
if($_SESSION['add-to-cart-item'][$i] == $stack_id)
{
unset($_SESSION['add-to-cart-item'][$stack_id]);
}
}
}
in your code
if($_SESSION['add-to-cart-item'][$i] == $stack_id)
{
unset($_SESSION['add-to-cart-item'][$stack_id]);
}
you find that $stack_id equals $_SESSION['add-to-cart-item'][$i] and not $i
which means that you need to unset $_SESSION['add-to-cart-item'][$i].
good luck
You should unset with [$i]
unset($_SESSION['add-to-cart-item'][$i]);