editing a JSON file

Viewed 645

First of all yes I did check other options, questions and answers but sadly those didn't work for me.

So I'm currently working on a small project including a shopping cart system. The shopping cart system is created by a PHP session and everything works fine. Products can be added, rows can be deleted and the cart can be cleared completely.

Now I would like to add some functions like counting the items in the cart, calculating the total price and VAT prices. Since the session is stored as a JSON object I'm able to use angularjs and $http.get() to read the JSON cart object and redefine the data so it's usable in an ng-repeat for the view.

So when the visitor clicks on the "add to cart" button the following code is creating the session:

session_start();

$product_id = $_REQUEST['product_id'];
$product_name = $_REQUEST['product_name'];
$product_price = round($_REQUEST['product_price'], 2);
$product_size = $_REQUEST['product_size'];
$product_quantity = $_REQUEST['product_quantity'];
$total_product_price = $product_price*$product_quantity;
round($total_product_price, 2);
// Add new item to session
$cartProduct = array(
    "id" => $product_id,
    "name" => $product_name,
    "price" => $product_price,
    "size" => $product_size,
    "quantity" => $product_quantity,
    "total_product_price" => $total_product_price,
    "total_items" => 0
);

/*
 * check if the 'cart' session array was created
 * if it is NOT, create the 'cart' session array
 */
if(empty($_SESSION['cart']["cartItems"])){
    $_SESSION['cart']["cartItems"] = array();
}

// check if the item is in the array, if it is, do not add
if(array_key_exists($product_id and $product_size, $_SESSION['cart'])){
    // redirect to product list and tell the user it was added to cart
    echo "<script> alert('Dit product staat al in de winkelwagen')</script>])";
}

// else, add the item to the array
else{
    $_SESSION['cart']["cartItems"][$product_id]=$cartProduct;
}

So my first attempt was to add the following to the section "add the item to the array"

    $arr = json_decode($_SESSION['cart']['cartItems'][$product_id], true);
    $total_items['total_items'] = count($_SESSION['cart']);
    array_push($arr['cartItems'], $total_items);

But sadly this didn't work. I also tried adding this to the getCart section.

session_start();

$json = json_encode($_SESSION['cart']["cartItems"]);
echo($json);

Sadly also without any result.

So my question is how am I able to add the total_items calculation to the array. And how am I able to calculate the total price, VAT prices etc?

PS: the JSON outcome of one product:

{"16":{"id":"16","name":"TestDatumProduct","price":1000,"size":"M","quantity":"4","total_product_price":4000,"total_items":0}}

UPDATE

So an update to combine the progress of the last few days:

So currently my code is based on the answer of @devionNL since i like the action method and the answer of @FranciscoRodríguez was barely an answer since he only adviced me about the counting method, (didn't work)

So using the action examples from @devionNL i've made some small changes and came up with the following code.

<?php
session_start();
$cartItemID = $_REQUEST['cartItem_id'];
$product_id = $_REQUEST['product_id'];
$product_name = $_REQUEST['product_name'];
$product_price = round($_REQUEST['product_price'], 2);
$product_size = $_REQUEST['product_size'];
$product_quantity = $_REQUEST['product_quantity'];
$total_product_price = $product_price*$product_quantity;
round($total_product_price, 2);

// Add new item to session
$cartProduct = array(
    "id" => $product_id,
    "name" => $product_name,
    "price" => $product_price,
    "size" => $product_size,
    "quantity" => $product_quantity,
    "total_product_price" => $total_product_price
);

// If the session is empty create an empty array
if(empty($_SESSION['cart']["cartItems"])){
    $_SESSION['cart']["cartItems"] = array();
}

// Add to cart
if ($_REQUEST['action'] == 'addToCart')
{
    if (array_key_exists($product_id, $_SESSION['cart']['cartItems']))
    {
        $_SESSION['cart']['cartItems']['totalItems']++;
    }
    else
    {
        $_SESSION['cart']['cartItems']['totalItems']++;
        array_push($_SESSION['cart']['cartItems'], $cartProduct );
    }
}

// RemoveRow
else if ($_REQUEST['action'] == 'removeRow') // If you want a delete action
{
    if (array_key_exists($product_id, $_SESSION['cart']['cartItems']))
    {
        if ($_SESSION['cart']['cartItems']['totalItems'] > 1)
        {
            foreach ($cartDecode as $key => $cartItem)
            {
                // IF THE TITLE MATCHES THE SIGNAL STRING
                if ($cartItem->{"id"} == $cartItemID)
                {
                    // REMOVE THIS OBJECT
                    unset($cartDecode[$key]);
                }

            }
            $_SESSION['cart']['cartItems']['totalItems']--; // Deduct by 1.
        }
    else
        {
            $_SESSION['cart']['cartItems'] = $cartProduct;
        }
    }

    $_SESSION['cart']['cartItems']['totalPrice'] = array_sum(array_map(function($item) {
        return $item['price'] * $item['totalItems'];
    },
        $_SESSION['cart']['cartItems']));

}
$cart = json_encode($_SESSION['cart']['cartItems']);
echo ($cart);

So adding to the cart, and calculating the cartItems is working as expected. But i still can't find the way of removing a row. inside the cart. Next to that i'm still struggling with getting the total price of the cart. The JSON outcome is as following:

{"totalItems":2,"0":{"id":"7","name":"Bedrukt jurkje van chiffon","price":20.5,"size":"M","quantity":"3","total_product_price":61.5},"1":{"id":"5","name":"Bedrukte Zomerjurk","price":30.5,"size":"M","quantity":"3","total_product_price":91.5}}

The full cart in JSON would then be:

{"cartItems":{"totalItems":2,"0":{"id":"7","name":"Bedrukt jurkje van chiffon","price":20.5,"size":"M","quantity":"3","total_product_price":61.5},"1":{"id":"5","name":"Bedrukte Zomerjurk","price":30.5,"size":"M","quantity":"3","total_product_price":91.5}}}

So my questions are? 1. How am i able to delete a single row (ID == "", Then delete) 2. How am i able to calculate the full price of the cart? 3. For placing the order inside the dabatase, how would i be able to select each row? (id, name, etc). I was thinking in the way of using a foreach() statement?

If there are any questions please ask them in the comments.

As always, Thanks in advance!

4 Answers

At first sight I can see some weird stuff going on here:

$arr = json_decode($_SESSION['cart']['cartItems'][$product_id], true);
$total_items['total_items'] = count($_SESSION['cart']);
array_push($arr['cartItems'], $total_items);

You are storing in $arr the json object of 1 single product. Then after you count the total ítems (actually you are counting the size of the cart root array) you try to store it inside an array at the key 'total_items'. Finally you try to append that whole array to the json object, at the key 'cartItems' (which also is not a key of a product)

What I think you are trying to do is simply this:

$_SESSION['cart']['cartSize'] = count($_SESSION['cart']['cartItems']);

The best approach is to have your product information stored in a database and not let the client send all that info to the server, since you cannot initially verify that the client is telling the truth (read: Never trust client input).

Basically what the client should send is only Add/Remove and the productId it wants to add, you can ofcourse then return the full object with price and such but the client shouldn't be able to 'update' that price.

This assumes $product_id contains the product to be add or removed.

session_start();

// If the cart or cartItems isn't set, create empty
if (empty($_SESSION['cart']) || empty($_SESSION['cart']['cartItems']))
{
   $_SESSION['cart'] = array();
   $_SESSION['cart']['cartItems'] = array();
   $_SESSION['cart']['totalPrice'] = 0;
   $_SESSION['cart']['totalItems'] = 0;
}

// Search the cartItems for the column named productId that matches the $product_id. This can return null, so always verify with !empty.

$arrayKeyId = array_search($product_id, array_column($_SESSION['cart']['cartItems'], 'productId'));

if ($_REQUEST['action'] == 'add')
{
  if (!empty($arrayKeyId)) // If it isn't empty, append to  the quantity
     $_SESSION['cart']['cartItems'][$arrayKeyId]['totalItems']++;
  else // It's new: Add it to the array
     $_SESSION['cart']['cartItems'][] = $cartProduct;
}
else if ($_REQUEST['action'] == 'delete') // If you want a delete action
{
  if (!empty($arrayKeyId))
  {
   // If more than 1 quantity, lower by 1 
   if ($_SESSION['cart']['cartItems'][$arrayKeyId]['totalItems'] > 1)
       $_SESSION['cart']['cartItems'][$arrayKeyId]['totalItems']--;
   else // Or if there was only 1, remove the item fully. 
      unset($_SESSION['cart']['cartItems'][$arrayKeyId]);
  }
}

// Total price based on item count times their price.
$_SESSION['cart']['totalPrice'] = array_sum(array_map(function($item) { 
    return $item['price'] * $item['totalItems']; 
}, $_SESSION['cart']['cartItems']));

// Total items based on the total amount of cartItems (without their quantity)
$_SESSION['cart']['totalItems'] = count($_SESSION['cart']['cartItems']);


echo json_encode($_SESSION['cart']['cartItems']);

I got a bit lost in here so forgive me if I'm wrong, hopefully it has the expected result :

<?php
session_start();
//unset($_SESSION['cart']);
var_dump($_SESSION['cart']['cartItems']);
$cartItemID = $Req['cartItem_id'];
$product_id = $Req['product_id'];
$product_name = $Req['product_name'];
$product_price = round($Req['product_price'], 2);
$product_size = $Req['product_size'];
$product_quantity = $Req['product_quantity'];
$total_product_price = $product_price*$product_quantity;
round($total_product_price, 2);

// Add new item to session
$cartProduct = array(
    "id" => $product_id,
    "name" => $product_name,
    "price" => $product_price,
    "size" => $product_size,
    "quantity" => $product_quantity,
    "total_product_price" => $total_product_price
);

// If the session is empty create an empty array
if(empty($_SESSION['cart']["cartItems"])){
    $_SESSION['cart']["cartItems"] = array();
    $_SESSION['cart']["cartItems"]["totalitems"] = 0;
    $_SESSION['cart']["cartItems"]["totalprice"] = 0;

}

// Add to cart
if ($Req['action'] == 'addToCart') {
    if (!isset($_SESSION['cart']["cartItems"][$cartItemID])) {
        $_SESSION['cart']["cartItems"][$cartItemID] = $cartProduct;
        $_SESSION['cart']["totalitems"]++;
        $_SESSION['cart']["totalprice"] += $total_product_price;
    }
}

// RemoveRow
else if ($Req['action'] == 'removeRow') // If you want a delete action
{
    if (isset($_SESSION['cart']["cartItems"][$cartItemID])) {
        $_SESSION['cart']["totalitems"]--;
        $_SESSION['cart']["totalprice"] -= $_SESSION['cart']["cartItems"][$cartItemID];
        unset($_SESSION['cart']["cartItems"][$cartItemID]);
    }

}
$cart = json_encode($_SESSION['cart']['cartItems']);
echo ($cart);

So to explain this. Use the "cartItemID" as the key for the "cartProduct". and have two more key in the "cart" array for the total item count and the total price. And to answer your questions :

  • The total price of the cart gonna be in "$_SESSION['cart']["totalprice"]"

  • To insert them into a database you can simply foreach the $_SESSION['cart']["cartItems"] array.

Ok I believe i make it work at least with my test data. I have put comments in code at every point i believe that requires a change. Also note that totalItems and totalPrice has to be in $_SESSION['cart'] and $_SESSION['cart']["cartItems"] has to maintain only the items array elese the array_map function that you want to make the sum will not work. Hope that helps you a bit.

session_start();
    $cartItemID = $_REQUEST['cartItem_id'];
    $product_id = intval($_REQUEST['product_id']); //if product_id is integer use intval
    $product_name = $_REQUEST['product_name'];
    $product_price = round(doubleval($_REQUEST['product_price']), 2);//if product_price is double use doubleval will help for the calculations
    $product_size = $_REQUEST['product_size'];
    $product_quantity = intval($_REQUEST['product_quantity']); //if product_quantity is integer use intval will help for the calculations
    $total_product_price = $product_price*$product_quantity; 
    round($total_product_price, 2);



    // Add new item to session
    $cartProduct = array(
        "id" => $product_id,
        "name" => $product_name,
        "price" => $product_price,
        "size" => $product_size,
        "quantity" => $product_quantity,
        "total_product_price" => $total_product_price
    );

    // If the session is empty create an empty array
    if(empty($_SESSION['cart']["cartItems"])){
        $_SESSION['cart']["cartItems"] = array();
    }

    // Add to cart
    if ($_REQUEST['action'] == 'addToCart')
    {
        if (array_key_exists($product_id, $_SESSION['cart']['cartItems']))
        {
            //$_SESSION['cart']['totalItems']++; //this line can cause problems when removing item out of the cart, when the user adds an item and you increment the total items value, you have to increment the value for the specific product in order to substract the correct number in the removal, 
            //you can use 2 approaches depending what you trying to achieve, 
            //1. if $_SESSION['cart']['totalItems'] is the items by type then you don't need to increment if item exists , just comment your line
            //2. if $_SESSION['cart']['totalItems'] represents the total number of items by adding the quantity of every product then this has to change use the following which i recommend
            $_SESSION['cart']['cartItems'][$product_id]['quantity']+=$product_quantity;
            $_SESSION['cart']['cartItems'][$product_id]['total_product_price']+=$total_product_price;
        }
        else
        {
            //$_SESSION['cart']['totalItems']++;
            //use this line for 2nd apporach
            $_SESSION['cart']['cartItems'][$product_id] = $cartProduct ; //array_push is wrong here you need a key that is the product id not the next available index, array_push will just give you the next available index, that's why the rest not working

        }
        //use this line for 2nd apporach
        $_SESSION['cart']['totalItems']+=$product_quantity;
    }

    // RemoveRow
    else if ($_REQUEST['action'] == 'removeRow') // If you want a delete action
    {
        if (array_key_exists($product_id, $_SESSION['cart']['cartItems']))
        {
            if ($_SESSION['cart']['totalItems'] > 1)
            {
                /*foreach ($cartDecode as $key => $cartItem)
                {
                    // IF THE TITLE MATCHES THE SIGNAL STRING
                    if ($cartItem->{"id"} == $cartItemID)
                    {
                        // REMOVE THIS OBJECT
                        unset($cartDecode[$key]);
                    }

                }*///cannot understand what you are trying to achieve here, but seems not wokring

                //$_SESSION['cart']['totalItems']--; // Deduct by 1. //again use this if you want 1st approach

                //use the following if you want the 2nd approach which i recommend
                $_SESSION['cart']['totalItems']-=$_SESSION['cart']['cartItems'][$product_id]['quantity'];
                unset($_SESSION['cart']['cartItems'][$product_id]); //this lines is working
            }
            else
            {
                $_SESSION['cart']['cartItems'] = $cartProduct;//what this line do, it seems a bit strange, not to say wrong...
            }
        }
    }

    $_SESSION['cart']['totalPrice'] = array_sum(array_map(function($item) {
        return $item['price'] * $item['quantity']; //it's quantity not totla_items
    }, //this calculation has to be outside of the else if ($_REQUEST['action'] == 'removeRow') in order to make the toal sum calculation in every pass
    $_SESSION['cart']['cartItems']));
    $cart = json_encode($_SESSION['cart']);
    echo ($cart);

And here are the test data i have used to check the code.

$_REQUEST['action'] = "addToCart";
//unset( $_SESSION['cart']);
/*$product_id = 7;
$product_name = "Bedrukt jurkje van chiffon";
$product_price = 20.5;
$product_size = "M";
$product_quantity = 1;
$total_product_price = 20.5;
*/
$product_id = 5;
$product_name = "Bedrukte Zomerjurk";
$product_price = 30.5;
$product_size = "M";
$product_quantity = 1;
$total_product_price = 30.5;

every time i run the script i comment / un comment and a product, change the $_REQUEST['action'] to removeRow in order to check the delete functionality.

Related