Jump to content

PHP Shopping Cart Update Basket Item


billy_111

Recommended Posts

Hey,

 

I am just finishing off my shopping cart however i have stumbled upon a problem.

 

When i add to basket i execute the following method:

 

    public function AddToCart(){
        !isset($_SESSION['ID']) ? $_SESSION['ID'] = array() : '';
        !isset($_SESSION['theName']) ? $_SESSION['theName'] = array() : '';
        !isset($_SESSION['quantity']) ? $_SESSION['quantity'] = array() : '';
        !isset($_SESSION['price']) ? $_SESSION['price'] = array() : '';
        !isset($_SESSION['image']) ? $_SESSION['image'] = array() : '';

        array_push($_SESSION['ID'], $_POST['ID']);
        array_push($_SESSION['theName'], $_POST['theName']);
        array_push($_SESSION['quantity'], $_POST['quantity']);
        array_push($_SESSION['price'], $_POST['price']);
        array_push($_SESSION['image'], $_POST['image']);
        $loc = $_SERVER['HTTP_REFERER'];
        echo "<script>window.location.href='".$loc."'</script>";
    } 

 

This creates the session as an array. Now lets say i click on the add to basket button twice for the same item. I don't want to have 2 instances of the same item which is what i have not, but i want to have the item name once and then 'x2' next to the quantity.

 

So moving on on my items page i have hidden input values which populates the basket session, shown below:

 

        <input type="hidden" name="ID" value="<?php echo $row['theID']; ?>" />
        <input type="hidden" name="theName" value="<?php echo $row['theName']; ?>" />
        <input type="hidden" name="price" value="<?php echo $row['price']; ?>" />
        <input type="hidden" name="image" value="<?php echo $row['image']; ?>" />
        <input type="hidden" name="quantity" value="1" />

 

Now what i have managed to do is when my basket is empty and i add an item to the basket multiple times the basket works exactly how i want. However when i then add a different item to the basket more than once it adds a quantity to both items.

 

This is because i need to target the specific item in the basket.

 

    if(isset($_POST['ID'])){
        if(!empty($_SESSION['theName'])){
           $i=0;
            foreach($_SESSION['theName'] as $name){
                if($_POST['theName'] == $name){
                    $_SESSION['quantity'][$i] = $_SESSION['quantity'][$i] + 1;
                }else {
                    $cart->AddToCart();
                }
            }
        }
    } 

 

I tested this code and clicked add to cart multiple times on 2 different items. I get this:

 

Dior - £69.99 x4

CK Top - £1.99 x1

CK Top - £1.99 x1

 

Now this item:

 

Dior - £69.99 x4

 

was actually x3 but when i clicked on a different item more than once it updated both items quantities.

 

So my question is, can i target a specific item in a session array and accomplish what i am trying to do?

 

Just to be clear, i need to in essence update the quantity of the item within the session array.

 

So for example if i add 3 items to my basket i will have 3 items in my array, would i be able to alter the second item in the array?

 

Many thanks.

 

Kind regards

Billy

Link to comment
Share on other sites

I see you are already using objects to handle it, however it's design is very inflexible (which is why you get these headaches).

 

class Cart {
  private $items = array();
  
  public function addItem(CartItem $item) {
    $object = $this->findItemByName($item->getName());
    if (null === $object) {
      $this->items[] = $object;
    }
  }
  
  public function findItemByName($name) {
    foreach ($this->items as $item) {
      if (0 === strcasecmp($name, $item->getName())) {
        return $item;
      }
    }
    return NULL;
  }
}

class CartItem {
  private $id = 0;
  private $name = '';
  private $quantity = 0;
  private $price = 0.0;
  private $image = '';
  
  public function getName() {
    return $this->name;
  }
  
  public function addQuantity($quantity) {
    if (!ctype_digit($quantity)) { throw new Exception(''); }
    if (0 > (int) $quantity) { throw new Exception(''); }
    
    $this->quantity += (int) $quantity;
    return $this;
  }
  
  public function equals(CartItem $item) {}
}

 

$cart = Cart::fromArray($_SESSION['cart']);
..

if (array_key_exists(array('id', 'name', 'quantity', 'price', 'image'), $_POST)) {
  $id = $_POST['id'];
  $name = $_POST['name'];
  ..
  
  $temp = new CartItem();
  $temp->setId($id);
  $temp->setName($name);
  $temp->setQuantity($quantity);
  ..
  
  $item = $cart->findItemByName($temp->getName());//or $cart->findItemById($temp->getId());
  if (NULL === $item) {//does not yet exists
    $cart->addItem($temp);
  } else {
    $item->addQuantity(1);
  }
  
  $_SESSION['cart'] = $cart->toArray();//store
}

Link to comment
Share on other sites

Hey,

 

Thanks so much for your code ignace. I have just started to go OO so apologies for it not being strong  :-[

 

Now the code you have suggested looks like a much better way however would this mean i have to change my whole class? Just to show you my full Cart class is shown below:

 

<?php
class Cart {

    public function sanitise($data) { // Escapes parameters before sending SQL query
        foreach($data as $key => $value){
            $data[$key] = $this->mysqli->real_escape_string($value);
        }
        return $data;
    }

    public function __construct($host, $username, $password, $dbname) {
        $this->mysqli = new mysqli($host, $username, $password, $dbname);
        if ($this->mysqli->errno){
            echo 'Unable to connect'.$this->mysqli->error;
            exit();
        }
    }

    public function AddToCart(){
        !isset($_SESSION['ID']) ? $_SESSION['ID'] = array() : '';
        !isset($_SESSION['theName']) ? $_SESSION['theName'] = array() : '';
        !isset($_SESSION['quantity']) ? $_SESSION['quantity'] = array() : '';
        !isset($_SESSION['price']) ? $_SESSION['price'] = array() : '';
        !isset($_SESSION['image']) ? $_SESSION['image'] = array() : '';

        array_push($_SESSION['ID'], $_POST['ID']);
        array_push($_SESSION['theName'], $_POST['theName']);
        array_push($_SESSION['quantity'], $_POST['quantity']);
        array_push($_SESSION['price'], $_POST['price']);
        array_push($_SESSION['image'], $_POST['image']);
        $loc = $_SERVER['HTTP_REFERER'];
        echo "<script>window.location.href='".$loc."'</script>";
    }
    
    public function getTotalPrice(){
        $i = 0;
        $total = 0;
        if(isset($_SESSION['quantity'])){
            foreach($_SESSION['price'] as $price){
                while(!isset($_SESSION['price'][$i]) && !isset($_SESSION['quantity'][$i])){
                    $i++;
                }
                $total = $total + ($price * $_SESSION['quantity'][$i]);
                $i++;
            }
        }
        return $total;
    }

    public function getTotalItems(){
        $total = 0;
        if(isset($_SESSION['quantity'])){
            foreach($_SESSION['quantity'] as $quantity){
                $total = $total + $quantity;
            }
        }
        return $total;
    }

    public function removeItem(){
        $id = $_GET['ID'];
        unset($_SESSION['ID'][$id]);
        unset($_SESSION['theName'][$id]);
        unset($_SESSION['price'][$id]);
        unset($_SESSION['quantity'][$id]);
    }

    public function emptyCart(){
        unset($_SESSION['ID']);
        unset($_SESSION['theName']);
        unset($_SESSION['price']);
        unset($_SESSION['quantity']);
    }

    public function addCustomerToSession(){
        $_SESSION['billingFirstName'] = $_POST['billingFirstName'];
        $_SESSION['billingSurname'] = $_POST['billingSurname'];
        $_SESSION['billingAddress1'] = $_POST['billingAddress1'];
        $_SESSION['billingAddress1'] = $_POST['billingAddress1'];
        $_SESSION['billingAddress2'] = $_POST['billingAddress2'];
        $_SESSION['billingCity'] = $_POST['billingCity'];
        $_SESSION['billingPostcode'] = $_POST['billingPostcode'];
    }

    public function insertOrder($data, $sessionID){
        $data = $this->sanitise($data);
        $i=0;
        session_start();
        foreach($_SESSION['ID'] as $ID):
            $sql = 'INSERT INTO hussaini_orders
            (userID, itemID, quantity, fname, sname, address1,
            address2, city, postcode, date_added) VALUES
            ('.$sessionID.', '.$ID.', '.$_SESSION['quantity'][$i].',
                \''.$data['billingFirstName'].'\', \''.$data['billingSurname'].'\',
                    \''.$data['billingAddress1'].'\', \''.$data['billingAddress2'].'\',
                        \''.$data['billingCity'].'\', \''.$data['billingPostcode'].'\', now())';
            $this->mysqli->query($sql) or die($this->mysqli->error);
            $i++;
        endforeach;
    }

    public function deductQuantitiesFromItems(){
        $i=0;
        session_start();
        foreach($_SESSION['ID'] as $ID):
        $sql = 'UPDATE hussaini_items SET
                    stock = stock - '.$_SESSION['quantity'][$i].' 
                    WHERE ID = '.$ID;
            $result = $this->mysqli->query($sql) or die($this->mysqli->query($sql));
            return $result;
        $i++;
        endforeach;
    }

    public function __destruct() {
        $this->mysqli->close();
    }
}

 

Is there a quick fix for me to go with? On my add to cart item page i have this in my controller:

 

<?php
$view->pageTitle = 'Manstore | Items';
require_once('Models/Items.class.php');
require_once('Models/Cart.class.php');

$items = new Items('localhost', 'root', '', 'test');
$cart = new Cart('localhost', 'root', '', 'test');

    session_start();

    if(isset($_GET['ID'])){
    $result = $items->selectItemsByID($_GET['ID']);
    }

    if(isset($_POST['ID'])){
        if(!empty($_SESSION['theName'])){
           $i=0;
            foreach($_SESSION['theName'] as $name){
                if($_POST['theName'] == $name){
                    $_SESSION['quantity'][$i] = $_SESSION['quantity'][$i] + 1;
                }else {
                    $cart->AddToCart();
                }
            }
        } else {
            $cart->AddToCart();
        }
    }
    
require_once('Views/view-item.phtml');

 

I need to set this site live soon so i was hoping i could get away with a quick fix for now and implementing a better method like yours later this week..

 

What do you think?

 

Again i appreciate your support.

 

Kind regards

Billy

Link to comment
Share on other sites

Well your current design is really inflexible due to $_POST, $_SESSION and the database being tightly coupled to your class. For highest flexibility you'd best remove all these dependencies like shown in my example.

 

I could easily modify my example to be used with a database instead of a $_SESSION.

 

$cart = Cart::fromArray($db->execute("SELECT * FROM cart WHERE user_id = {$_SESSION['user_id']}")->fetchAll());
..

if (array_key_exists(array('id', 'name', 'quantity', 'price', 'image'), $_POST)) {
  $id = $_POST['id'];
  $name = $_POST['name'];
  ..
  
  $temp = new CartItem();
  $temp->setId($id);
  $temp->setName($name);
  $temp->setQuantity($quantity);
  ..
  
  $item = $cart->findItemByName($temp->getName());//or $cart->findItemById($temp->getId());
  if (NULL === $item) {//does not yet exists
    $cart->addItem($temp);
  } else {
    $item->addQuantity(1);
  }
  
  foreach ($cart->toArray() as $item) {//store
    $db->execute("INSERT INTO cart (id, name, quantity, price, image) VALUES ({$item['id']}, {$item['name']}, {$item['quantity']}, {$item['price']}, {$item['image']})
      ON DUPLICATE KEY UPDATE quantity = quantity + 1");
  }
}

 

See, how easily I modified my code to match the new setting.

Link to comment
Share on other sites

I need to set this site live soon so i was hoping i could get away with a quick fix for now and implementing a better method like yours later this week..

 

This is the kind of thinking you need to get away from. Transforming your application from a badly-designed to a well-designed is not an easy task. Don't forget you are actually rewriting the application which means you put in twice the effort required then if you would have if you would have thought-out the application design.

 

Well, look over my code. All you need is go over all stored items and check if it already exists if so then update otherwise create.

 

I have just started to go OO so apologies for it not being strong

 

If you are working against a deadline then I don't understand why you would start out with something you barely understand? Why didn't you stick to the things you understand?

Link to comment
Share on other sites

Hey,

 

Thanks for the advice, this is actually a learning curve  for me and once the site is finished it is checked by another developer, who i could just ask but i want to learn myself as it's the best way.

 

I appreciate your suggestions and will definitely try follow your code and try to understand how it works.

 

Thanks again

Link to comment
Share on other sites

once the site is finished it is checked by another developer, who i could just ask but i want to learn myself as it's the best way

 

You are better off on these forums, nothing guarantee's that what he said is true or that he is the most knowledgeable on the subject. These forums on the other hand have a good deal of highly educated/experienced professionals recognizable by the tag below their name (Guru, Administrator, ..).

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.